下面的C++ 11代码应该如何工作?

Ser*_*bir 6 gcc clang visual-c++ c++11

以下代码在各种编译器上输出不同的结果:

  • 在Visual Studio 2013上的2,1,2
  • Visual Studio 2015上的2,2,2
  • 关于GCC5/c ++ 14的2,1,1
  • 使用Microsoft Codegen在Clang 3.7上获得2,2,2
  • 在Ubuntu 14.04下的Clang 3.6/c ++ 11上的2,1,2

最后,它应该如何按照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

Yak*_*ont 5

您的程序在C++ 11中格式不正确,因为您创建了一个std::vector类型不完整的类型作为参数.创建类型时,vector 必须完成a的值std::vector<T>类型.

作为一个不正确的程序(我不知道诊断的要求),任何和所有行为在标准下都是合法的.

该要求vectorT是一个完整的类型可能已经结束指定的(实在是没有说服力的理由有要求),但它的存在.在C++ 1z中提出相同的问题将导致不同的答案,因为该要求被放宽了.


哲学上忽略了这个问题:

Array a1 = { 1, 2 };
Run Code Online (Sandbox Code Playgroud)

这应该生成一个std::vector有两个元素.

foo(a1);
Run Code Online (Sandbox Code Playgroud)

这应该传递a1foo,因为类型完全匹配.

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>.