Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use explicit specifier for multi-argument constructors?

I have recently learned about the explicit specifier.

Suppose we have:

f( W, W, W );

Now if we do

f( 42, 3.14, "seven" );

The compiler will attempt the following implicit conversions:

f( W(42), W(3.14), W("seven") );

If we have defined matching constructors for W, namely:

W(int);
W(double);
W(std::string);

...it will succeed.

However, if we make the first one explicit:

explicit W(int);

... this disables the implicit conversion.

You would now have to write:

f( W(42), 3.14, "seven" );

i.e. it is forcing you to explicitly state the conversion

Now on to the question:

It is possible to write:

explicit W(int,int); // 2 arguments!

This compiles!

But I can't see any corresponding scenario that might require this syntax.

Can anyone provide a minimal example?

like image 653
P i Avatar asked Dec 25 '14 08:12

P i


1 Answers

If your constructor is explicit and the class doesn't supply a non-explicit constructor taking initializer_list<T>, then you cannot copy-list-initialize an instance.

W w = {1,2}; // compiles without explicit, but not with

Simple live example

#include <iostream>

class A
{
public:
   explicit A(int, int) {}
};

class B
{
public:
    B(int, int) {}
};

int main()
{
   B b = {1,2};
   A a = {1,2};
}

Quotes from standard:

8.5/16

— If the initializer is a (non-parenthesized) braced-init-list, the object or reference is list-initialized (8.5.4).

8.5.4/3

List-initialization of an object or reference of type T is defined as follows: ...

Otherwise, if T is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen through overload resolution (13.3, 13.3.1.7). If a narrowing conversion (see below) is required to convert any of the arguments, the program is ill-formed.

like image 141
ForEveR Avatar answered Sep 19 '22 10:09

ForEveR