首页 > 解决方案 > 关于 C++ 标准的歧义

问题描述

根据此代码:

#include <iostream>
using namespace std;
struct T {
    T() { cout << "default"<<endl; }
    T(string s) { cout << "ctor "<< endl; }
    T(const T& t) { cout << "copy ctor"<< endl; }
};
int main()
{
    T x = T(T(T()));
    return 0;
}

输出 :

default

并根据标准

(17) 初始化器的语义如下。目标类型是正在初始化的对象或引用的类型,源类型是初始化表达式的类型。如果初始化器不是单个(可能是带括号的)表达式,则未定义源类型。

......

(17.6.1) 如果初始化表达式是纯右值并且源类型的 cv 非限定版本与目标类是同一类,则初始化表达式用于初始化目标对象。[例子:T x = T(T(T())); 调用 T 默认构造函数来初始化 x。——结束示例]

它在 c ++ 11 (GNU GCC v7.1.1) 中给出了相同的结果

第一个问题:此语句中是否定义了源类型?

T x = T(T(T()));

现在,如果我们将此函数添加到此代码中:

string f(T t) {return "str";}

并替换T x = T(T(f(T())));T x = T(T(T()));

输出 :

default
ctor

现在定义了源类型吗?

不是T()初始化表达式吗?

如果是,按照标准,应该调用默认构造函数,但是为什么要T(string s)为x调用呢?

标签: c++c++11language-lawyer

解决方案


此语句中是否定义了源类型?

T x = T(T(T()));

是的,因为T(T(T()))是单个表达式;在这种情况下,它可以被paranthesized。

同样的道理适用于

T(T(f(T())))

因为这也是一个表达式。


不是 T() 初始化表达式吗?

一般来说,当然,但不是在上述情况下。=和之间的整个表达式;是初始化表达式。


但是为什么要为 x 调用 T(string s)?

因为有一个显式调用f返回 a string,并且该参数用于构造 a T,它调用string构造函数。

T x = T(  T(f(  T()  ))  );
             // ^^^      calls the default constructor
       // ^^^^^^^^^^^^^  calls the string constructor
   

推荐阅读