The following code outputs different results on various compilers:
Finally, how it should work according to C++ standard?
#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 }));
}
P.S. The same issue reveals with json_spirit library from this article: http://www.codeproject.com/Articles/20027/JSON-Spirit-A-C-JSON-Parser-Generator-Implemented
Your program is ill-formed in C++11, as you have created a std::vector type with an incomplete type as an argument. The value type of a vector must be complete when you create the std::vector<T> type.
As an ill-formed program (and I'm not aware of a requirement for a diagnostic), any and all behavior is legal under the standard.
The requirement that vector's T be a complete type is probably over-specified (there is really no convincing reason to have that requirement), but it exists. Asking the same question in C++1z will lead to a different answer, as that requirement was relaxed.
Ignoring that issue, philosophically:
Array a1 = { 1, 2 };
this should generate a std::vector with two elements.
foo(a1);
This should pass a1 to foo, as the types match exactly.
foo(Array{ a1 });
Here we have {}. My rule of thumb with {} is "if it is non-empty, and it can match an initializer_list constructor, it must".
As a1 can be converted to a Value, Array{ a1 } is an array of one Value.
foo(Array({ a1 }));
Here we look at an argument of the constructor Array that can be called with { a1 }. Both the std::initalizer_list<Value> and the Array&& constructors can be.
Which is called should not matter: The Array&& constructor in turn sends the {a1} to the std::initalizer_list<Value> constructor.
So my opinion is that it should print 211. This is, however, merely an opinion on what the could ought to do, not an analysis of what the standard says it should do, as the C++11 standard quite clearly states your program is ill-formed.
On the other hand, hiding the copy constructor seems rude.
On the final hand, you did write a simply insane type. Insane behavior is to be expected.
A more practical concern might be when the Value type has a template constructor that happens to also match a std::vector<Value>.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With