如何从类中获取成员函数的返回类型?

时间:2014-10-18 00:15:14

标签: c++ clang return-type-deduction

以下程序会产生clang的编译错误,但会传递给其他编译器:

#include <utility>

struct foo
{
  auto bar() -> decltype(0)
  {
    return 0;
  }

  using bar_type = decltype(std::declval<foo>().bar());
};

int main()
{
  return 0;
}

clang收益:

$ clang -std=c++11 clang_repro.cpp 
clang_repro.cpp:10:48: error: member access into incomplete type 'foo'
  using bar_type = decltype(std::declval<foo>().bar());
                                               ^
clang_repro.cpp:3:8: note: definition of 'foo' is not complete until the closing '}'
struct foo
       ^
1 error generated.

此程序是否非法,如果是,是否有正确的方法来定义foo::bar_type

clang详细信息:

$ clang --version
Ubuntu clang version 3.5-1ubuntu1 (trunk) (based on LLVM 3.5)
Target: x86_64-pc-linux-gnu
Thread model: posix

2 个答案:

答案 0 :(得分:9)

g++4.9 issues the same error

我不确定这是否是无效代码,因为declval允许不完整的类型,并且不评估decltype中的表达式。
rightføld in his answer非常清楚为什么这段代码无效。

您可以使用std::result_of

using bar_type = std::result_of<decltype(&foo::bar)(foo)>::type;

实际上是这样实现的:

using bar_type = decltype((std::declval<foo>().*std::declval<decltype(&foo::bar)>())());

这与问题中的代码之间的区别在于使用指向成员的运算符(.*)而不是成员访问运算符(.),并且它没有要求类型完整,这由以下代码证明:

#include <utility>
struct foo;
int main() {
    int (foo::*pbar)();
    using bar_type = decltype((std::declval<foo>().*pbar)());
}

答案 1 :(得分:6)

§7.1.6.2说:

  

对于表达式edecltype(e)表示的类型定义如下:

     
      
  • 如果e是未加密码的id-expression或未加括号的类成员访问(5.2.5),decltype(e)是由e命名的实体的类型。 ...
  •   
  • ...
  •   

§5.2.5说:

  

对于第一个选项(点),第一个表达式应具有完整的类类型。 ...

§9.2说:

  

在类说明符的结束},类被视为完全定义的对象类型(3.9)(或完整类型)。 ...

decltype(std::declval<foo>().bar())(反过来std::declval<foo>().bar())出现在结束}之前,因此foo不完整,因此std::declval<foo>().bar()格式不正确,所以铿锵是对的。