模板成员函数的编译时间推导

Compile time deduction of template member function

是否可以在编译时获取模板成员函数的return类型?

我想我需要一些类似的东西:

template<class T>
struct SomeClass
{  
     // T must have a function foo(int), but do not know the
     // return type, it could be anything
     using RType = ??? T::foo(int) ???; // Is it possible to deduce it here?
}

如果您知道函数调用的参数类型,则以下方法应该有效:

template<typename T>
struct X
{
  typedef typename decltype(std::declval<T>.foo(std::declval<int>())) type;
};

如果你不这样做,你仍然可以推断出函数指针的类型并提取 return 类型:

template<class F>
struct return_type;

template<class C, class R, class... Args>
struct return_type<R(C::*)(Args...)>
{ using type = R; };

template<typename T>
struct X
{
  typedef typename return_type<decltype(&T::foo)>::type type;
};

如果 T::foo 是重载函数或 T 的成员,这将失败。

不幸的是,如果你知道你将用什么参数调用它,那么只有知道某些表达式的 return 类型才有可能(不幸的是,这通常与你需要知道的地方不同return 类型)...

使用decltype operator together with the std::declval模板可以实现您想做的事情。

decltype(<i>EXPRESSION</i>) 在编译时产生 <i>EXPRESSION</i> 会有。 <i>EXPRESSION</i> 本身永远不会被评估。这很像 sizeof(<i>EXPRESSION</i>) returns <i>EXPRESSION</i> 计算为 to 但从未实际计算过它。

只有一个问题:您的 foo 是一个非 static 成员函数,因此写 decltype(T::foo(1)) 是一个错误。我们需要以某种方式获得 T 实例 。即使我们对它的构造函数一无所知,我们也可以使用 std::declval 来获取对它的实例的引用。这纯粹是编译时的事情。 std::declval 实际上从未定义(仅声明),所以不要尝试在 运行 时对其求值。

这是组合在一起的样子。

#include <type_traits>

template <typename SomeT>
struct Something
{
  using RetT = decltype(std::declval<SomeT>().foo(1));
};

要了解它是否确实有效,请考虑这个示例。

struct Bar
{
  float
  foo(int);
};

struct Baz
{
  void
  foo(int);
};

int
main()
{
  static_assert(std::is_same<float, Something<Bar>::RetT>::value, "");
  static_assert(std::is_same<void, Something<Baz>::RetT>::value, "");
}

虽然这符合我认为您的要求,但如果您尝试使用 T 实例化 Something<T> 而不是 一个合适的 foo 成员,你会得到一个硬编译器错误。最好将类型计算移动到模板参数中,这样您就可以从 SFINAE 规则中受益。

template <typename SomeT,
          typename RetT = decltype(std::declval<SomeT>().foo(1))>
struct Something
{
   // Can use RetT here ...
};