You'd stumble upon it for brace initialization (for instance in arrays)
struct A {
explicit A( int b, int c ) {}
};
struct B {
B( int b, int c ) {}
};
int main() {
B b[] = \{\{1,2}, {3,5}}; // OK
A a1[] = {A{1,2}, A{3,4}}; // OK
A a2[] = \{\{1,2}, {3,4}}; // Error
return 0;
}
Up until C++11, yeah, no reason to use explicit on a multi-arg constructor.
That changes in C++11, because of initializer lists. Basically, copy-initialization (but not direct initialization) with an initializer list requires that the constructor not be marked explicit.
Example:
struct Foo { Foo(int, int); };
struct Bar { explicit Bar(int, int); };
Foo f1(1, 1); // ok
Foo f2 {1, 1}; // ok
Foo f3 = {1, 1}; // ok
Bar b1(1, 1); // ok
Bar b2 {1, 1}; // ok
Bar b3 = {1, 1}; // NOT OKAY
The excellent answers by @StoryTeller and @Sneftel are the main reason. However, IMHO, this makes sense (at least I do it), as part of future proofing later changes to the code. Consider your example:
class A {
public:
explicit A( int b, int c );
};
This code doesn't directly benefit from explicit.
Some time later, you decide to add a default value for c, so it becomes this:
class A {
public:
A( int b, int c=0 );
};
When doing this, you're focussing on the c parameter - in retrospect, it should have a default value. You're not necessarily focussing on whether A itself should be implicitly constructed. Unfortunately, this change makes explicit relevant again.
So, in order to convey that a ctor is explicit, it might pay to do so when first writing the method.
As you can easily see, explicit prevents from using initializer list alongside with bar function bacause the constructor of struct Bar is declared as explicit.