计算函数指针的类型 [英] Computing the type of a function pointer

查看:166
本文介绍了计算函数指针的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下内容:

template<typename T>
struct S
{
    typedef M< &T::foo > MT;
}

这将适用于:

S<Widget> SW;

其中 Widget :: foo()是一些功能

我将如何修改 struct S 的定义以允许以下内容:

How would I modify the definition of struct S to allow the following instead:

S<Widget*> SWP;


推荐答案

您需要的是以下类型转换。

What you need is the following type transformation.


  • 给出 T ,返回 T

  • 给出 T * ,返回 T

  • given T, return T
  • given T *, return T

碰巧标准库已经在 std :: remove_pointer (尽管做起来并不难)。

It so happens that the standard library already has implemented this for us in std::remove_pointer (though it's not hard to do yourself).

这样,您就可以使用object_type = std :: remove_pointer_t< T>来写

With this, you can then write

using object_type = std::remove_pointer_t<T>;
using return_type = /* whatever foo returns */;
using MT = M<object_type, return_type, &object_type::foo>;

关于您还想使用智能指针的评论,我们必须重新定义类型

Regarding your comment that you also want to work with smart pointers, we have to re-define the type transformation.


  • 给定智能指针类型 smart_ptr< T> ,返回 smart_ptr< T> :: element_type ,应为 T

  • 给出一个指针键入 T * ,返回 T

  • 否则,给出 T ,返回 T 本身

  • given a smart pointer type smart_ptr<T>, return smart_ptr<T>::element_type, which should be T
  • given a pointer type T *, return T
  • otherwise, given T, return T itself

为此,我们必须编写自己的元函数。至少,我不知道标准库中有什么对这里有帮助的。

For this, we'll have to code our own meta-function. At least, I'm not aware of anything in the standard library that would help here.

我们首先定义主要的模板

We start by defining the primary template (the "otherwise" case).

template <typename T, typename = void>
struct unwrap_obect_type { using type = T; };

第二个(匿名)类型参数,默认为 void 将在以后使用。

The second (anonymous) type parameter that is defaulted to void will be of use later.

对于(原始)指针,我们提供了以下部分专业化。

For (raw) pointers, we provide the following partial specialization.

template <typename T>
struct unwrap_obect_type<T *, void> { using type = T; };

如果我们在这里停止,基本上可以得到 std :: remove_pointer 。但是,我们将为智能指针添加额外的部分专业化。当然,我们首先必须定义什么是智能指针。就本示例而言,我们将使用嵌套的 typedef 名为 element_type 的每个类型作为智能指针。

If we'd stop here, we'd basically get std::remove_pointer. But we'll add an additional partial specialization for smart pointers. Of course, we'll first have to define what a "smart pointer" is. For the purpose of this example, we'll treat every type with a nested typedef named element_type as a smart pointer. Adjust this definition as you see fit.

template <typename T>
struct unwrap_obect_type
<
  T,
  std::conditional_t<false, typename T::element_type, void>
>
{
  using type = typename T::element_type;
};

第二种类型参数 std :: conditional_t< false,类型名称T :: element_type,void> 是一种模拟 <$ c $的复杂方法c> 14中的c> std :: void_t 。这个想法是,我们具有以下部分类型函数。

The second type parameter std::conditional_t<false, typename T::element_type, void> is a convoluted way to simulate std::void_t in C++14. The idea is that we have the following partial type function.


  • 给出了类型 T 嵌套名为 element_type 的嵌套 typedef ,返回 void

  • 否则,触发替换失败

  • given a type T with a nested typedef named element_type, return void
  • otherwise, trigger a substitution failure

因此,如果我们要处理智能指针,我们将获得比主要模板更好的匹配,否则,SFINAE将从进一步考虑中删除此部分专业化。

Therefore, if we are dealing with a smart pointer, we'll get a better match than the primary template and otherwise, SFINAE will remove this partial specialization from further consideration.

这是一个可行的例子。 TC 建议使用 std :: mem_fn 来调用成员函数。

Here is a working example. T.C. has suggested using std::mem_fn to invoke the member function. This makes the code a lot cleaner than my initial example.

#include <cstddef>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <utility>

template <typename ObjT, typename RetT, RetT (ObjT::*Pmf)() const noexcept>
struct M
{
  template <typename ThingT>
  static RetT
  call(ThingT&& thing) noexcept
  {
    auto wrapper = std::mem_fn(Pmf);
    return wrapper(std::forward<ThingT>(thing));
  }
};

template <typename T, typename = void>
struct unwrap_obect_type { using type = T; };

template <typename T>
struct unwrap_obect_type<T *, void> { using type = T; };

template <typename T>
struct unwrap_obect_type<T, std::conditional_t<false, typename T::element_type, void>> { using type = typename T::element_type; };

template <typename T>
struct S
{

  template <typename ThingT>
  void
  operator()(ThingT&& thing) const noexcept
  {
    using object_type = typename unwrap_obect_type<T>::type;
    using id_caller_type          = M<object_type, int,                &object_type::id>;
    using name_caller_type        = M<object_type, const std::string&, &object_type::name>;
    using name_length_caller_type = M<object_type, std::size_t,        &object_type::name_length>;
    std::cout << "id:          " << id_caller_type::call(thing)          << "\n";
    std::cout << "name:        " << name_caller_type::call(thing)        << "\n";
    std::cout << "name_length: " << name_length_caller_type::call(thing) << "\n";
  }

};

class employee final
{

 private:

  int id_ {};
  std::string name_ {};

 public:

  employee(int id, std::string name) : id_ {id}, name_ {std::move(name)}
  {
  }

  int                  id()          const noexcept { return this->id_; }
  const std::string&   name()        const noexcept { return this->name_; }
  std::size_t          name_length() const noexcept { return this->name_.length(); }

};

int
main()
{
  const auto bob = std::make_shared<employee>(100, "Smart Bob");
  const auto s_object = S<employee> {};
  const auto s_pointer = S<employee *> {};
  const auto s_smart_pointer = S<std::shared_ptr<employee>> {};
  s_object(*bob);
  std::cout << "\n";
  s_pointer(bob.get());
  std::cout << "\n";
  s_smart_pointer(bob);
}

这篇关于计算函数指针的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆