For those of you familiar with the latest C++ standard, what do you think of uniform initialization? Listening to folks like Herb Sutter, it seems like the intended purpose is to be completely pervasive, which obviously changes the look and feel of C++.

Do you plan on using it everywhere possible? Only in places where narrowing conversions are problematic? Never at all because it's ugly? ;) This seems like the most potentially controversial new feature of the language.

Personally, I'm still on the fence about it. On the one hand it seems ugly and awkward, and on the other there are distinct benefits (especially pedagogical) that would justify the ugliness, iff it's widely adopted amongst C++ programmers and not just the elite.

Recommended Answers

All 6 Replies

After reading that wiki link you provided I am not a big fan. In order for it to work the person using it will need to know the internals of the class to know what to pass. To me this harms encapsulation. I dont think I'll be using it unless like you said deceptikon,

iff it's widely adopted amongst C++ programmers and not just the elite.

I read that article from Wikipedia in its full length a month ago or so. From what I noticed, the general idea of those changes is to make C++ more competitive and I agree with most of those changes.

About uniform initialization, that may come from the languages where the variables don't have type definitions and use tuples as one of the basic containers (like Erlang). That feature has its own merits in speeding up the development of a code, but, definitely, it has its pitfalls as well.

I am not CS/SE to be able to speak about its ugliness or beauty, but having some experience with Erlang, I can say that this is one of the features pretty useful, if not for anything else, at least for speeding up code development.

My 2c opinion.

Uniform initialization refers to this, correct?

class xypoint
{
    public:
        float x;
        float y;

        xypoint(float xx, float yy) : x{xx}, y{yy}
        {
        }
};

xypoint returnpoint(void)
{
    //Equivalent to "return xypoint(3, 4);"
    return {3, 4};
}

I don't see what's so controversial about it. To me, it just looks like an alternate syntax for calling a constructor. On one hand, things could get ugly because you end up calling a function when all you think you're doing is initializing a few data feilds. On the other hand, I really enjoy how much verbosity it has the potential to eliminate. I'll probably use it sparingly.

I remember, early on when learning C++, to be a bit frustrated at limitations of C-style struct initialization and how awkwardly it mixed with C++ classes. But I also remembered letting go of that quite quickly and never really missing it. Now that the rules have been updated to more or less solve those tiny frustrations, I'm glad about it, but also very indifferent to it. I don't think I'll use that feature much, not because I have a problem with it, but just because I don't really have a problem (anymore) with the way it was before (C++03) and I'm used to that. If anything, it might push me to initialize C-style structs (or POD-types) with the curly-brace syntax a bit more often, now that it has more of a C++ flavor to it.

Saying the feature is "contraversial", I think that goes too far. Is it ugly? Well, that doesn't really have an answer. I think it's ok. Does it have issues about implicit conversions? No more than C++03 single-parameter constructors. And I don't see any other practical concerns you might raise. I think this feature is closer to being one of the least contraversial ones rather than one of the most contraversial. But then again, the C++11 standard is still very conservative overall, you can argue that certain changes are less consequential than others, but most of the contraversial stuff hasn't made it to the C++11 standard.

Saying the feature is "contraversial", I think that goes too far.

Note that I called it potentially controversial. I can't say it's controversial when there's no controversy to speak of yet. But given syntax shifts in the past, I can safely say that more than a few people will be vocal about it if it starts to get used regularly in place of assignment or paren-style initialization. ;)

And by "controversial" I mean the usual holy wars about style, not any technical flaws in the feature.

Well, brace-enclosed initialization solves the 'most vexing parse' problem quite nicely.

struct A { A() ; /* ... */ } ;
struct B { B(A) ; /* ... */ } ;

B b1 ( A() ) ; // declares a function b1
B b2 { A{} } ; // defines an object b2
B b3 ( ( A() ) ) ; // defines an object b3

.
.
Uniform initialization syntax is extremely useful in generic code. For instance T is a template type parameter and we want to use T(), uniform initialization with T{} takes the intricacies of C++'s parsing rules out of the equation. Also, we can now deal with types logically - 'T is a type that can be initialized with four integers' - without having to special case for aggregate initialization, constructor initialization, initializer_list initialization.

template < typename T > T foo() { return T{ 0, 1, 2, 3 } ; }

auto vec = foo< std::vector<int> >() ;
auto tup = foo< std::tuple<int,long,double,double> >() ;
struct A { int a, b ; long c, d ; } ;
A a = foo<A>() ;

.
.

it seems like the intended purpose is to be completely pervasive

It can't be completely pervasive. For that to be possible, brace-enclosed initialization would have to be a drop-in replacement for all older initialization constructs, and it isn't that.
For one, uniform initialization and initialization via initializer lists use the same syntactic construct.

std::vector<int> a ( 100, 7 ) ; // two arg constructor; a.size() == 100, a[0] == 7
std::vector<int> b { 100, 7 } ; // initializer list; a.size() == 2, a[0] == 100

.

And two, it can behave differently when aggregate type semantics of a C-style array are involved.

std::array<int,10> aa ;
std::array<int,10> bb (aa) ;
std::array<int,10> cc {aa} ; // error, std::array<> has aggregate semantics

.
.

Does it have issues about implicit conversions? No more than C++03 single-parameter constructors.

It actually soves one issue; errors due to unanticipated narrowing conversions. But for that we needn't use 'pure' brace-enclosed initialization syntax; we can also use it with C++03 constructor syntax.

std::vector<int> a ( 100.3 ) ; // a.size() == 100, a[0] == 7
std::vector<int> b ( { 100.3 } ) ; // error, narrowing conversion

.
.

And by "controversial" I mean the usual holy wars about style, not any technical flaws in the feature.

The conflict with initializer lists is controversial, it has been the subject of some heated debate, and that is not a debate about style. If we uniformly construct all our objects using uniform initialization {}, and at some point of time, a type adds a constructor taking an initializer list, all our initialization code for that type breaks. From a software engineering perpective, this kind of fragility is unacceptable in a large code base.

It is no surprise that a majority of people who write real life production code, and have been enthusiastic about incorporating C++11 features into their code base, have baulked at pervasive use of uniform initialization. Among all the new features that C++11 has added, widespread use of uniform initialization is perhaps the most controversial. There are very few early adopters.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.