Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/144.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 计算函数指针的类型_C++_C++11_Template Meta Programming_Dependent Name - Fatal编程技术网

C++ 计算函数指针的类型

C++ 计算函数指针的类型,c++,c++11,template-meta-programming,dependent-name,C++,C++11,Template Meta Programming,Dependent Name,考虑以下几点: template<typename T> struct S { typedef M< &T::foo > MT; } 您需要的是以下类型转换 给定T,返回T 给定T*,返回T 碰巧的是,标准库已经在中为我们实现了这一点(尽管自己实现并不困难) 有了这个,你就可以写了 using object_type = std::remove_pointer_t<T>; using return_type = /* whatever f

考虑以下几点:

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

您需要的是以下类型转换

  • 给定
    T
    ,返回
    T
  • 给定
    T*
    ,返回
    T
碰巧的是,标准库已经在中为我们实现了这一点(尽管自己实现并不困难)

有了这个,你就可以写了

using object_type = std::remove_pointer_t<T>;
using return_type = /* whatever foo returns */;
using MT = M<object_type, return_type, &object_type::foo>;
默认为
void
的第二个(匿名)类型参数将在以后使用

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

template <typename T>
struct unwrap_obect_type<T *, void> { using type = T; };
第二个类型参数
std::conditional\u t
是在C++14中进行模拟的一种复杂方式。我们的想法是,我们有下面的部分类型函数

  • 给定一个名为
    元素的嵌套
    typedef
    类型
    T
    ,返回
    void
  • 否则,触发替换失败
因此,如果我们处理智能指针,我们将获得比主
模板更好的匹配,否则,SFINAE将从进一步考虑中删除此部分专门化

下面是一个工作示例。已建议使用调用成员函数。这使得代码比我最初的示例更清晰

#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);
}
#包括
#包括
#包括
#包括
#包括
#包括
模板
结构M
{
模板
静态RetT
调用(ThingT&&thing)不例外
{
自动包装器=std::mem_fn(Pmf);
返回包装器(std::forward(thing));
}
};
模板
结构展开对象类型{using type=T;};
模板
结构展开对象类型{using type=T;};
模板
结构展开对象类型{using type=typename T::element\u type;};
模板
结构
{
模板
无效的
运算符()
{
使用对象类型=类型名称展开对象类型::类型;
使用id\u caller\u type=M;
使用name\u caller\u type=M;
使用name_length_caller_type=M;

std::cout它应该只对指针有效还是对指针和非指针都有效?问题中的一些东西不清楚:什么是
M
?如何将
Widget::foo
连接到您实例化的类型?您试图实现什么?理想情况下,它应该对指针和非指针都有效,但我甚至会非常赞同关联一个单独使用指针类型的结构版本。@ChrisBeck:我真正想要完成的是:谢谢,我现在得到了它;正在处理一个答案。“注意,为了实际调用成员函数,我必须引入一个有条件地取消引用指针的帮助器。”我们有
INVOKE
。@T.C.好吧,我们会有…但即使这样,will
std::INVOKE
也会自动调用
(o.*pmf)(
(p->*pmf)(
),这取决于可调用对象是否是指针?我们已经有了它(通过
mem\u fn
)。是的,它会处理去引用(它确实是
(*pmf)()
这样它甚至可以与智能指针一起工作,并且不会被
->*
重载所混淆)。此外,这里可调用的是PMF,而不是对象/指针。@5gon12eder谢谢!我自己试图解决这个问题时确实看到了std:remove_指针,但是,我觉得它不适用于智能指针类型。这是真的吗?@unshul它不适用于智能指针,而且你在你的操作中没有提到智能指针。我也不知道确实需要这样做,因为如果您有一个智能指针容器,那么在智能指针本身上调用成员函数(如
get
)不是更有用吗?无论如何,我也更新了智能指针的答案。
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;
};
#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);
}