原型与decltype和auto

时间:2016-05-12 11:40:07

标签: c++ templates c++14 auto decltype

考虑以下课程:

class MyClass
{
    int _id;
public:
    decltype(_id) getId();
};

decltype(MyClass::_id) MyClass::getId()
{
    return _id;
}

它汇编得很好。

然而,当我从中制作模板类时:

template <class T>
class MyClass
{
    int _id;
public:
    decltype(_id) getId();
};

template <class T>
decltype(MyClass<T>::_id) MyClass<T>::getId()
{
    return _id;
}

我明白了:

test.cpp:10:27: error: prototype for 'decltype (MyClass<T>::_id) MyClass<T>::getId()' does not match any in class 'MyClass<T>'
 decltype(MyClass<T>::_id) MyClass<T>::getId()                                                                                
                           ^
test.cpp:6:19: error: candidate is: decltype (((MyClass<T>*)(void)0)->MyClass<T>::_id) MyClass<T>::getId()
     decltype(_id) getId();
                   ^

为什么?
为什么选择不同类型

  • decltype (MyClass<T>::_id) MyClass<T>::getId()
  • decltype (((MyClass<T>*)(void)0)->MyClass<T>::_id)

我可以通过在类中定义主体来修复它:

template <class T>
class MyClass
{
    int _id;
public:
    decltype(_id) getId() { return _id; }
};

尾随返回类型遇到类似的问题:

template <class T>
class MyClass
{
    int _id;
public:
    auto getId() -> decltype(_id);
};

template <class T>
auto MyClass<T>::getId() -> decltype(MyClass<T>::_id)
{
    return _id;
}

错误:

test.cpp:10:6: error: prototype for 'decltype (MyClass<T>::_id) MyClass<T>::getId()' does not match any in class 'MyClass<T>'
 auto MyClass<T>::getId() -> decltype(MyClass<T>::_id)
      ^
test.cpp:6:10: error: candidate is: decltype (((MyClass<T>*)this)->MyClass<T>::_id) MyClass<T>::getId()
     auto getId() -> decltype(_id);
          ^
  • decltype (MyClass<T>::_id) MyClass<T>::getId()
  • decltype (((MyClass<T>*)this)->MyClass<T>::_id) MyClass<T>::getId()

g ++ 5.3.0

2 个答案:

答案 0 :(得分:3)

根据标准草案N4582 §5.1.1/ p13一般[expr.prim.general] Emphasis Mine ):

  

表示非静态数据成员或非静态数据的id表达式   只能使用类的成员函数:

     

(13.1) - 作为类成员访问(5.2.5)对象的一部分   表达式是指成员的类 63 或类   派生自该类,或

     

(13.2) - 形成指向成员(5.3.1)或

的指针      

(13.3) - 如果该id-expression表示非静态数据成员及其   出现在未评估的操作数中。 [实施例:

struct S {
int m;
};
int i = sizeof(S::m); // OK
int j = sizeof(S::m + 42); // OK
     

- 结束示例]

     

63)当对象表达式是隐式时,这也适用   (* this)(9.3.1)。

同样来自§7.1.6.2/ p4简单类型说明符[dcl.type.simple] Emphasis Mine ):

  

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

     

(4.1) - 如果e是未表示的id-expression或未表示的   类成员访问(5.2.5),decltype(e)是实体的类型   以e命名。如果没有这样的实体,或者e命名一组   重载函数,程序格式不正确;

     

(4.2) - 否则,如果e是xvalue,decltype(e)T&&,其中   T是[{1}};

的类型      

(4.3) - 否则,如果e是左值,edecltype(e),其中T&   是T;

的类型      

(4.4) - 否则,edecltype(e)的类型。

     

e说明符的操作数是未评估的操作数(第5条)。

     

[实施例:

decltype
     

- 结束示例] [注意:确定涉及的类型的规则   decltype(auto)在7.1.6.4中规定。 - 结束说明]

因此,由于const int&& foo(); int i; struct A { double x; }; const A* a = new A(); decltype(foo()) x1 = 17; // type is const int&& decltype(i) x2; // type is int decltype(a->x) x3; // type is double decltype((a->x)) x4 = x3; // type is const double& 是未评估的操作数,因此代码是合法的并且应该编译。

一个干净的解决方法是使用decltype

decltype(auto)

以上代码被GCC / CLANG / VC ++接受。

答案 1 :(得分:1)

似乎是GCC Bug 57712

错误描述的示例代码:

  generic_equiv             code
0  0101010C0AAAAAA  0101010C0BBAAAA
1  0101010F0AAAUAU  0101010F0BCAAAU
2              NaN  0101010G0AAABAB