Ser*_*bir 6 gcc clang visual-c++ c++11
以下代码在各种编译器上输出不同的结果:
最后,它应该如何按照C++标准工作?
#include <iostream>
#include <vector>
#include <stdio.h>
using namespace std;
class Value;
using Array = std::vector<Value>;
class Value
{
public:
Value(const Array &)
{
}
Value(int)
{
}
};
void foo(Array const& a)
{
printf("%d\n", (int)a.size());
}
int main()
{
Array a1 = { 1, 2 };
foo(a1);
foo(Array{ a1 });
foo(Array({ a1 }));
}
Run Code Online (Sandbox Code Playgroud)
PS同样的问题也来自本文的json_spirit库:http://www.codeproject.com/Articles/20027/JSON-Spirit-AC-JSON-Parser-Generator-Implemented
您的程序在C++ 11中格式不正确,因为您创建了一个std::vector类型不完整的类型作为参数.创建类型时,vector 必须完成a的值std::vector<T>类型.
作为一个不正确的程序(我不知道诊断的要求),任何和所有行为在标准下都是合法的.
该要求vector的T是一个完整的类型可能已经结束指定的(实在是没有说服力的理由有要求),但它的存在.在C++ 1z中提出相同的问题将导致不同的答案,因为该要求被放宽了.
哲学上忽略了这个问题:
Array a1 = { 1, 2 };
Run Code Online (Sandbox Code Playgroud)
这应该生成一个std::vector有两个元素.
foo(a1);
Run Code Online (Sandbox Code Playgroud)
这应该传递a1给foo,因为类型完全匹配.
foo(Array{ a1 });
Run Code Online (Sandbox Code Playgroud)
我们在这里{}.我的经验法则{}是"如果它是非空的,它可以匹配initializer_list构造函数,它必须 ".
作为a1可转化为一个Value,Array{ a1 }是一个数组Value.
foo(Array({ a1 }));
Run Code Online (Sandbox Code Playgroud)
这里我们看一下Array可以调用的构造函数的参数{ a1 }.无论是std::initalizer_list<Value>和Array&&构造函数就可以了.
调用哪个应该无关紧要:Array&&构造函数又将构造函数发送{a1}给std::initalizer_list<Value>构造函数.
所以我的意见是它应该打印211.这一点,但是,仅仅是在什么可能的意见应该做的,没有什么标准说,它应该做的,因为C++标准的11十分清楚地指出你的程序的分析是形成不良.
另一方面,隐藏拷贝构造函数似乎很粗鲁.
最后,你确实写了一个简单的疯狂类型.疯狂的行为是可以预期的.
更实际的问题可能是当Value类型的template构造函数碰巧也匹配a时std::vector<Value>.