【问题标题】:Compile time deduction of template member function模板成员函数的编译时间扣除
【发布时间】:2015-03-10 22:55:58
【问题描述】:

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

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

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?
}

【问题讨论】:

  • decltype 不起作用吗?我不确定您的问题到底是什么。另外,foostatic 成员函数吗?如果没有,您可能需要使用decltype(std::declval&lt;T&gt;().foo(1))。还是您想要foo 本身的类型(例如int(int))?
  • 所以,foo 不是静态成员函数,我只想要 foo 的返回类型。例如,如果 foo 返回 int,我想要 int,如果 foo 返回 bool,我想要那个。现在,我不知道如何使它与 decltype 一起使用,这是正确的使用方法,因为我在编译时需要它吗?我会试试你的建议,看看是否可行,谢谢。

标签: templates c++11 member-functions


【解决方案1】:

您想要做的可以通过使用decltype 运算符和std::declval 模板来实现。

decltype(<i>EXPRESSION</i>) 产生 - 在编译时 - <i>EXPRESSION</i> 将具有的类型。 <i>EXPRESSION</i> 本身永远不会被评估。这很像 sizeof(<i>EXPRESSION</i>) 返回任何 <i>EXPRESSION</i> 计算结果的大小,而无需实际计算它。

只有一个问题:你的foo 是一个非static 成员函数,所以写decltype(T::foo(1)) 是一个错误。我们需要以某种方式获取Tinstance。即使我们对它的构造函数一无所知,我们也可以使用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&lt;T&gt;,这并不理想987654341@ 成员,你会得到一个硬编译器错误。最好将类型计算移到模板参数中,这样您就可以从SFINAE 规则中受益。

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

【讨论】:

  • 这太棒了!我不确定 decltype 是否在编译时工作(这有点令人困惑,因为它看起来像是在调用构造函数)。现在还有一个问题 - 假设 foo 采用 SomeObj& 而不是 int 并且 SomeObj 没有默认构造函数。在那种情况下我将如何使用 decltype?
  • 在这种情况下,您需要使用另一个std::declval&lt;SomeObj&amp;&gt;() 作为参数。
  • 我明白了!非常感谢。
  • 第二段中的declval(EXPRESION)不应该改为decltype(EXPRESION)吗?
  • 是的,很好看。感谢@JonathanWakely 的纠正(连同我的其他错别字)。
【解决方案2】:

如果您知道函数调用的参数类型,那么以下应该可以工作:

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

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

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 的成员,这将失败。

不幸的是,如果您知道要使用哪些参数调用某个表达式,则只有可能知道该表达式的返回类型(不幸的是,这通常与您需要知道返回类型的地方不同).. .

【讨论】:

    猜你喜欢
    • 2015-11-26
    • 1970-01-01
    • 1970-01-01
    • 2013-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多