Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why some types does not work with uniform initialization syntax?

While updating some of my C++98 code to C++11, I noticed uniform initialization is not so uniform. Some of them related to incomplete type like void, while other are related to pod. e.g. For trivially copyable types, uniform initialization is not working for both direct initialization or copy initialization, when initialization involves copy/move constructor.

e.g.

template<class T>
T foo() { return T("Hello World");}
foo<void>();
foo<std::string>();
--------
template<class T>
T foo() { return T{"Hello World"};}
foo<void>();
foo<std::string>();

While the first part compiles, the second half fails with error: compound literal of non-object type 'void'

struct pod { int x;int y;};
pod p{1,2}; //ok pod p(1,2) is error as usual
pod p2(p);

struct foo
{
    foo(foo const& rhs) : p_(rhs.p_){}
    pod p_;
};
--------
struct pod { int x;int y;};
pod p{1,2}; 
pod p2{p};

struct foo
{
    foo(foo const& rhs) : p_{rhs.p_}{}
    pod p_;
};

Here also, the second half fails on copy construction with error: cannot convert 'pod' to 'int' in initialization. Though I think, this pod class is a trivial type (or even can be trivially copyable type) in c++11, but the problem remains same except primitive types

NOTE:

while the following works,

struct conv
{
    operator int()const { return 1;}
};
pod p{1,2};
pod p2{conv{}};

This does not,

struct conv
{
    operator pod()const { return pod{1,2};}
};
pod p{1,2};
pod p2{conv{}};

I also noticed C array does work with uniform initialization, but not with copy/move constructor. But that may be due to array being an aggregate which does not have copy/move constructor or assignment. Though I do not know why in c++11 those syntax are not allowed(specifically when they are class member, implicit copy/move does exactly that).

So, why can't I blindly change all C++98 initialization to C++11 style uniform initialization (Well , except for the types which has initializer list ! ) ?

I am using GCC 4.8.1

like image 960
abir Avatar asked Oct 03 '13 08:10

abir


1 Answers

"Uniform initialization" is a non-standard term which was used somewhat unfortunately in promotion of the initializer-list feature during its proposal phase.

No, you can't use it everywhere. In my experience, it's best to restrict it to

  • aggregates (with no constructor; C++98 already allowed this but C++11 extends support)
  • sequences (initializer_list)
  • return by value expressions calling a non-explicit constructor

Blindly changing everything and expecting no semantic change is just argumentum ad novitatem — doing something because it's new and different, not because it's appropriate.

As for generic programming, yes it's hard to correctly support situations spanning the above categories. Post specific complaints to the message board at http://isocpp.org and perhaps the guys in charge of the language will work harder to restore the generic order which "uniform initialization" was supposed to improve, not aggravate :v) .

like image 52
Potatoswatter Avatar answered Oct 14 '22 14:10

Potatoswatter