The Impact of "Explicit" Constructors in Overload Resolution

why the following code does not compile, and when I delete the explicit keyword before the constructor in class A, does it compile?

Using Visual Studio 2013:

enum E { e1_0, e1_1 }; template<typename T> struct A { A() {} explicit A(unsigned long) {} A(T) {} }; struct B { B() {} B(E) {} }; void F(B) {}; void F(A<short>) {}; void test() { F(e1_0); } 

Error:

 1>------ Build started: Project: exp_construct_test, Configuration: Debug Win32 ------ 1> exp_construct_test.cpp 1>e:\exp_construct_test\exp_construct_test.cpp(23): error C2668: 'F' : ambiguous call to overloaded function 1> e:\exp_construct_test\exp_construct_test.cpp(19): could be 'void F(A<short>)' 1> e:\exp_construct_test\exp_construct_test.cpp(18): or 'void F(B)' 1> while trying to match the argument list '(E)' ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ========== 

Edit: I downloaded clang and compiled clang-cl, which reports an error for both cases. As noted in the comments, the ambiguity is between A<short>(short) and B(E) .

So maybe there is a mistake in VC ++: when I remove explicit from A(unsigned long) , the compiler, by some intention, chooses B (E) instead of raising an ambiguity error. Can someone confirm the behavior of clang as standard, and VC ++ - buggies?

I added

 void G(E) {}; void G(short) {}; 

and call in G:

 G(e1_0); 

This does not cause any errors. Why is G(E) taught here, and in the case of candidates A<short>::A(short) and B::B(E) are they ambiguous?

Edit end

Thanks --joja

+5
source share
1 answer

Look at the different variations of your example one by one.

  • The initial example calling f(e0) .

     enum E {e0, e1}; template<typename T> struct A { A(); // (1) explicit A(unsigned long); // (2) A(T); // (3) }; struct B { B(); // (4) B(E); // (5) }; void f(A<short>); // (6) void f(B); // (7) void g(E); // (8) void g(short); // (9) 

    Among the three possibilities

    • convert e0 to unsigned long , create from it A<short> through constructor (2) and reload the call (6),
    • convert e0 to short , create A<hort> from it via constructor (3) and reload the call (6) and
    • create B from e0 through constructor (5) and reload the call (7)

    the first option is not applicable, because (2) is explicit . The other two include a custom transformation that is considered equally good, and none of them are accepted in favor of the other. The call is ambiguous, and the program is poorly formed.

  • Remove explicit from the constructor and call f(e0) .

     template<typename T> struct A { A(); // (1) A(unsigned long); // (2) A(T); // (3) }; struct B { B(); // (4) B(E); // (5) }; 

    Three options remain unchanged, but this time all three are applicable, and the call (even more) is ambiguous, and the program is poorly formed.

  • Make both constructors explicit and call f(e0) .

     template<typename T> struct A { A(); // (1) explicit A(unsigned long); // (2) explicit A(T); // (3) }; struct B { B(); // (4) B(E); // (5) }; 

    This makes it impossible to implicitly construct A<short> , and the call uniquely refers to overload (5).

  • Create constructor B explicit and call f(e0) .

     template<typename T> struct A { A(); // (1) explicit A(unsigned long); // (2) explicit A(T); // (3) }; struct B { B(); // (4) explicit B(E); // (5) }; 

    This time, none of the three conversion paths is applicable, since each of them will go through the explicit constructor. There is no overload f that is applicable and the program is poorly formed.

  • Call g(e0) .

    Here we have two possibilities:

    • Call overload (8) without conversion or
    • convert e0 to short and reload the call (9).

    Among these two, the first option is clearly favorable, because it does not involve transformation. The call is clear. (Even if constructor (5) is not explicit .)

Note that the default constructors (1) and (4) do not actually contribute anything to this discussion. Testing with GCC 4.9.1, all five examples behave as expected.

+3
source

Source: https://habr.com/ru/post/1214256/


All Articles