When to use explicit?

I've been working recently on a library of sorts and I want to make sure I am programming everything "safely". One thing I have never been sure of is when to use the keyword explicit on my constructors.

I have heard various thoughts on the topic:
- Use it when the constructor has one and only one argument.
- Use it only on the default, copy, and move constructor.
- Don't worry about it.

None of the explanations I have heard line up with each other and I am just thoroughly confused on the topic. What are the thoughts of everyone here as to the best use of the explicit keyword in order to create and maintain safe and effective programs?

Thanks!
Tresky
Use it when the constructor has one and only one argument
It has meaning only when applied to constructor which can be called with exactly 1 argument provided. (Either it has 1 argument or has default values for all other)

Use it only on the default, copy, and move constructor.
It is actually useless for them: default constuctor does not have arguments, and move and copy constructors parameters already has the type of that class, so no implicit conversion could happen even in theory.

Gold rule is to use explicit keyword for all constructors which can be called with one argument provided unless you want to enable implicit conversion from argument type.
What is the reason for not using explicit if the constructor has more than 1 argument provided? Why does it only meaning if there is only 1 argument?
because explicit prevents implicit conversions. They are performed by calling a constructor with argument compatible with converted value. You cannot call constructor with more than 1 argument providing only one. So other constructors cannot be called for implicit conversions and explicit will do nothing to them as there is nothing to prevent.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct foo
{
    foo() {} //Cannot be called for implicit conversion
    foo(int) {} //Can be called for implicit conversion
    explicit foo(double) //Cannot be called for implicit conversion
    foo(int, int) {} //Not explicit, cannot be called for implicit conversion 
}

void bar(foo);

int main()
{
    bar(foo()); //legal
    bar(10); //Illegal, foo(int) is explicit
    bar(2.0); //Legal foo(double) is not explicit
}
Oh! I've got it!

So, you can passfoo's argument(s) into the bar function and C++ will implicitly convert that into a foo object. However, bar will throw an error if you give it more than 1 argument because that is how it is defined, so therefore it is impossible for you, as the programmer, to pass it more than 1. By that fact, constructors with more than 1 argument need not be declared explicit.

Is this correct?
Yes. It is correct.

also if bar would be defined as void bar(foo, ...); The reason would still stand: you can provide more than one argument, but they would be threated as second, third, etc argument and not related to first foo object at all.
It has meaning only when applied to constructor which can be called with exactly 1 argument provided.

That was before C++11. Today you can have implicit conversions for multi-parameter constructors.

1
2
3
4
5
6
7
8
9
10
11
12
13
struct foo
{
    foo(double, double) {}
    explicit foo(int, int) {}
};

void bar(foo);

int main()
{
    bar({1.0, 1.0}); // valid
    bar({1, 1}); // invalid
}
Oh, thanks for correction. Never though that it is implicit conversion.

Well then it is not as important to make multiargument constructors explicit, as they are hard to invoke accidentally.
It might make sense if there is initializer_list constructor around and some other constructor which might accidently be threated as valid match if you accidentaly ake initializer_list constructor unviable in your call.
You'd usually like to leave ctors no-explicit if you want transparent wrappers, like smart pointers.
Last edited on
Topic archived. No new replies allowed.