Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between T t {x} and T t = { x } for integral or enumeration type?

In C++14:

For any integral or enumeration type T and for any expression expr:

Is there ever a difference between:

struct S { T t { expr }; };

and

struct S { T t = { expr }; };

Update:

I got to [dcl.init.list]p3b5 which says:

If the initializer list has a single element of type E and either T is not a reference type or its referenced type is reference-related to E, the object or reference is initialized from that element.

I believe this quote applies to both direct-list-initialization and copy-list-initialization.

So I think the answer is no, there is no difference.

like image 940
Andrew Tomazos Avatar asked Nov 20 '15 17:11

Andrew Tomazos


2 Answers

If you take a look at direct initialization and copy initialization references, you will find the same words:

if T is a non-class type, standard conversions are used, if necessary, to convert the value of other to the cv-unqualified version of T

so there should be no difference. The difference of these initializations only applies for class types: copy initialization does not consider explicit constructors and explicit user-defined conversion operators, direct initialization does. Integral and enumeration types have neither of them.

Edit:
@ᐅ Johannes Schaub - litb ᐊ answered a relative question to this one (only about parentheses, instead of braces) and he referenced 8.5/14 with similar wording (emphasis mine):

The form of initialization (using parentheses or =) is generally insignificant, but does matter when the initializer or the entity being initialized has a class type; see below. If the entity being initialized does not have class type, the expression-list in a parenthesized initializer shall be a single expression.

I could not find the {} counterpart in the standard, either. I hope that this is enough arguments to support the there's no difference answer.

like image 114
LogicStuff Avatar answered Nov 04 '22 04:11

LogicStuff


  1. struct S {T t { expr };}; is a non-static data member initializer that does not use the equals sign.
  2. struct S{T t = { expr };}; is a non-static data member initializer that uses the equals sign.

The first case is a direct-list-initialization while the second is a copy-list-initialization.

The difference between direct-list-initialization and copy-list-initialization is that for the first case both explicit and non-explicit constructors are considered, while for the second only non-explicit constructors may be called.

To clarify, consider the following example:

struct Foo {
  int i;
  explicit Foo(int i_) : i(i_) {}
};

struct Bar {
  Foo f {1};  
};

Live Demo

In this example Foo has an explicit constructor and Bar direct initializes its member f of type Foo. The example code compiles fine since for direct initialization both explicit and non-explicit constructors are considered.

Now we alter the example by transforming the non-static data member initializer with no use of equal sign, that is a case of direct-list-initialization to a non-static data member initializer with use of equal sign, which is a case of copy-list-initialization.

struct Foo {
  int i;
  explicit Foo(int i_) : i(i_) {}
};

struct Bar {
  Foo f = {1};  
};

Live Demo

Now the above example doesn't compile and emits an error:

error: chosen constructor is explicit in copy-initialization

This is expected because as already been mentioned in copy-list-initialization only non-explicit constructors may called.

Now for enumerators and other integral types, the difference displayed above won't apply (i.e., no constructors are involved). As such, the two statements (i.e., [1] and [2]) would be equivalent.

But for completeness sake, lets consider the following examples:

enum class Foo {A, B, C};

struct Bar {
  Foo f{Foo::A};  
};

and

enum class Foo {A, B, C};

struct Bar {
  Foo f = {Foo::A};  
};

Both the examples compile fine.

Also consider the following examples:

struct Bar {
  int i {1};  
};

and

struct Bar {
  int i = {1};  
};

Both examples also compile fine.

like image 40
101010 Avatar answered Nov 04 '22 05:11

101010