原型与decltype和auto不匹配

prototype mismatch with decltype and auto

本文关键字:auto 不匹配 decltype 原型      更新时间:2023-10-16

考虑以下类:

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

根据标准草案N4582§5.1.1/13 General[expr.prim.General]Emphasis Mine):

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

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

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

(13.3)--如果id表达式表示非静态数据成员,并且出现在未求值的操作数中。[示例:

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):

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

(4.1)——如果e是未加括号的id表达式或未加括号类成员访问(5.2.5),decltype(e)是实体的类型由e命名。如果没有这样的实体,或者如果e命名一组函数过载,程序格式错误;

(4.2)——否则,如果e为x值,则decltype(e)T&&,其中CCD_ 11是CCD_;

(4.3)——否则,如果e为左值,则decltype(e)T&,其中T是CCD_ 16的类型;

(4.4)——否则,decltype(e)e的类型。

decltype说明符的操作数是未赋值的操作数(第5条)

[示例:

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(auto)在7.1.6.4中有规定。——尾注]

因此,由于decltype是未赋值的操作数,因此代码是合法的,应进行编译。

一个干净的解决方法是使用decltype(auto):

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

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

这似乎是g++错误。

我已经在Visual Studio 2015中试用了您的代码:

生成:1成功,0失败,0最新,0跳过

编辑:我找到了解决方法:

#include <iostream>
template <class T>
class MyClass
{
    T _id = {0};
public:
    decltype(((MyClass<T>*)nullptr)->_id) getId();
};
template <class T>
decltype(((MyClass<T>*)nullptr)->_id) MyClass<T>::getId()
{
    return _id;
}
int main()
{
    MyClass<int> f;
    auto n = f.getId();
    std::cout << n << 'n'; // output: 0
}

输出:

0

这似乎是GCC Bug 57712。

错误描述的示例代码:

struct Test {
  int method(int value) { return value; }
  template <typename T>
  auto test(T value) -> decltype(this->method(value));
};
template <typename T>
auto Test::test(T value) -> decltype(this->method(value)) {
  return this->method(value);
}