使用 decltype 理解类型推导

non*_*ick 3 c++ reference

考虑以下 C++ 代码:

#include <bits/stdc++.h>

template <typename T> void print_type() { std::cout << __PRETTY_FUNCTION__ << std::endl; }

class Base{
    int num;
public:
    Base() : num{0} {}

    friend std::ostream & operator << ( std::ostream& stream, Base & obiekt){
        stream<< "num: " << obiekt.num;
        return stream;
    }
};

int main(){
    Base a{};
    std::cout << a << std::endl;
    std::cout << "type of a: " << std::endl;
    print_type < decltype( a ) > (); 

    std::cout << "type of (a): " << std::endl;
    print_type < decltype( (a) ) > ();


    Base b();
    std::cout << b << std::endl;

    std::cout << "type of b: " << std::endl;
    print_type < decltype( b ) > (); 

    std::cout << "type of (b): " << std::endl;
    print_type < decltype( (b) ) > (); 


    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我用 g++ 7.2.0 编译它,并得到以下输出:

num: 0
type of a: 
void print_type() [with T = Base]
type of (a): 
void print_type() [with T = Base&]
1
type of b: 
void print_type() [with T = Base()]
type of (b): 
void print_type() [with T = Base (&)()]
Run Code Online (Sandbox Code Playgroud)

我的问题:

  • 为什么std::cout << b << std::endl;打印“1”?
  • Base()像or 这样的类型是什么Base (&)()
  • (a)为什么有类型Base&,什么时候a有类型Base

我正在寻找答案,但找不到。我知道在这种情况下我应该使用不带任何括号的声明Base a;,但我想知道Base a;,Base a{};和之间的区别Base a();。为什么它在没有任何警告或错误的情况下进行复制?感谢帮助。

Edg*_*jān 5

主要问题是:

Base b();
Run Code Online (Sandbox Code Playgroud)

不按你的想法做。事实上,它是一个函数的声明,该函数接受零个参数并返回一个类型的对象Base


为什么 std::cout << b << std::endl; 打印“1”?

因为b是一个指向函数的指针。结果,过载:

basic_ostream& operator<<( bool value );
Run Code Online (Sandbox Code Playgroud)

被使用并被1打印为指向函数的指针永远不会为空。

一个更有趣的问题是为什么 gcc 甚至接受代码并且只产生警告。function 没有定义b,只有它的声明,所以我希望代码不会链接。


Base() 或 Base (&)() 等类型是什么?

Base()是一个指向函数的指针,不接受任何参数,并且 return Base,Base (&)()是对同一函数的引用。


为什么 (a) 的类型是 Base&,而 a 的类型是 Base?

因为decltype 这样工作

decltype(expression)
Run Code Online (Sandbox Code Playgroud)

如果参数是不带括号的id 表达式或不带括号的类成员访问表达式,则 decltype 生成由此表达式命名的实体的类型。如果没有这样的实体,或者参数指定了一组重载函数,则程序的格式不正确。

如果参数是 T 类型的任何其他表达式,并且

a) 如果表达式的值类别是 xvalue,则 decltype 产生 T&&;

b)如果表达式的值类别是左值,则 decltype 产生 T&

c) 如果表达式的值类别是纯右值,则 decltype 产生 T。