是否应忽略显式复制构造函数?

Should an explicit copy constructor be ignored?

这是一个小例子,它展示了一个不清楚的时刻

struct CL
{
    CL(){}
    CL(int){}
    explicit CL(const CL&){}
};

int main() {
    CL cl1;
    CL cl2=5;     //(1)
    CL cl3=(CL)5; //(2)
    return 0;
}

CL class 具有来自 int 的转换构造函数和标记为显式的复制构造函数。在 (1) 情况 5 (int) 中隐式转换为 CL,然后直接初始化 cl2。在 (2) 的情况下,cl3 被复制初始化。在这两种情况下,都必须涉及显式复制构造函数。但是不同的编译器给出不同的结果:

clang与VS:第一种情况是对的,第二种情况是错误的
gcc: 两种情况都是错误的

我认为 clang 和 VS 是正确的,因为根据标准 "explicit" 关键字阻止在复制初始化中使用构造函数,但在直接初始化中则不然,而 gcc 是错误的,因为直接初始化应用于(1) 个案.
谁是正确的编译器?

§ 12.3.1 [class.conv.ctor]/p2:

An explicit constructor constructs objects just like non-explicit constructors, but does so only where the direct-initialization syntax (8.5) or where casts (5.2.9, 5.4) are explicitly used.

示例 1:

CL cl2 = 5;

§ 8.5 [dcl.init]/p17:

The function selected is called with the initializer expression as its argument; if the function is a constructor, the call initializes a temporary of the cv-unqualified version of the destination type. The temporary is a prvalue. The result of the call (which is the temporary for the constructor case) is then used to direct-initialize, according to the rules above, the object that is the destination of the copy-initialization.

在直接初始化中,可以考虑explicit个构造函数,所以不会出现错误。 GCC trunk 已经编译了这个例子successfully. This was bug 54521


示例 2:

CL cl3 = (CL)5;

在这种情况下,转换语法执行 static_cast:

§ 5.2.9 [expr.static.cast]/p4:

An expression e can be explicitly converted to a type T using a static_cast of the form static_cast<T>(e) if the declaration T t(e); is well-formed, for some invented temporary variable t (8.5). The effect of such an explicit conversion is the same as performing the declaration and initialization and then using the temporary variable as the result of the conversion.

rhs 是 CL 类型,并且(复制)初始化需要非 explicit 构造函数,因此错误在意料之中。