为什么编译器在使用decltype时不会推断出成员的类型?

keb*_*ebs 12 c++ decltype language-lawyer c++11

我只是在自己的代码中注意到了这种行为,所以这是一个天真的问题:

这个:

struct A
{
    int get()
    {
        return a;
    }
    int a=1;
};   
int main() {}
Run Code Online (Sandbox Code Playgroud)

编译当然很好,虽然当成员数据的声明谎言之后的函数定义.

但后来我不明白为什么这样:

struct A
{
    auto get() -> decltype(a)
    {
        return a;
    }
    int a=1;
};  
Run Code Online (Sandbox Code Playgroud)

不编译(*).我要写这个:

struct A
{
    int a=1;
    auto get() -> decltype(a)
    {
        return a;
    }
};  
Run Code Online (Sandbox Code Playgroud)

有什么语言相关的原因,为什么它不好,或者只是编译器没有实现它?无论类成员的顺序如何,我都希望有相同的行为.

(*)通过Ideone.com使用gcc 6.3进行测试

Nel*_*eal 5

在你的第一个例子中,A::get声明,然后A::a声明,然后才定义(因为A完全声明)A::get.此时A::get,编译器知道A::a.

考虑这种等效形式:

struct A
{
    int get();
    int a=1;
};

inline int A::get()
{
    return a;
}
Run Code Online (Sandbox Code Playgroud)

对于第二个例子,这不可编译:

struct A
{
    auto get() -> decltype(a); // What is "a"?
    int a=1;
};

inline auto A::get() -> decltype(A::a)
{
    return a;
}
Run Code Online (Sandbox Code Playgroud)

声明类型时必须遵守相同的"声明顺序",例如:

struct A
{
    using IntType = int;
    auto get() -> IntType;
    int a=1;
};
Run Code Online (Sandbox Code Playgroud)

你不能这样写:

struct A
{
    using IntType = decltype(a);
    auto get() -> IntType;
    int a=1;
};
Run Code Online (Sandbox Code Playgroud)

另请注意,这不仅限于返回类型:参数类型也是函数声明的一部分.所以这也不编译:

struct A
{
    void f(decltype(a));
    int a=1;
};
Run Code Online (Sandbox Code Playgroud)

  • @Bathsheba为什么不呢?声明`size_t get()`不包含关于`a`的任何内容. (2认同)

Bat*_*eba 5

如果可能的话,一个非正式的回答:decltype是一个红鲱鱼.

return编译器在第一次传递时需要看到类型的所有部分.

例如,

template <size_t N> struct T{};

struct A
{
    T<sizeof(a)> get()
    {
        return T<sizeof(a)>();
    }
    int a;
};
Run Code Online (Sandbox Code Playgroud)

也会因为同样的原因而失败:如果int a;以前见过编译通过get().

  • 对于那些(像我一样)从未听说过的人:https://en.wikipedia.org/wiki/Red_herring ;-) (3认同)