How to disambiguate this construction in a templated conversion operator?

后端 未结 2 1068
北恋
北恋 2021-02-13 20:40

After being confused why my code gave me an ambiguity error on GCC but no errors on Clang, I simplified the code. It can be seen below.

struct Foo
{
    // Foo(F         


        
2条回答
  •  栀梦
    栀梦 (楼主)
    2021-02-13 21:27

    To resolve the ambiguity, add explicit to the conversion operator declaration:

    struct Bar
    {    
        template
        explicit operator T()
        {
            return Foo{nullptr}; 
        }
    };
    

    Why is it necessary? Because Foo has a constructor taking a int*, and so a operator int*() instantiation of operator T() template is being considered as part of overload resolution for the initialization of f. See under [over.match.copy]:

    1 [...] Assuming that cv1 T is the type of the object being initialized, with T a class type, the candidate functions are selected as follows:

    • (1.1) The converting constructors of T are candidate functions.

    • (1.2) When the type of the initializer expression is a class type “cv S”, the non-explicit conversion functions of S and its base classes are considered. When initializing a temporary object ([class.mem]) to be bound to the first parameter of a constructor where the parameter is of type “reference to possibly cv-qualified T” and the constructor is called with a single argument in the context of direct-initialization of an object of type “cv2 T”, explicit conversion functions are also considered.

    From (1.2) it follows that only implicit conversion functions are considered for the initialization, hence the ambiguity -- as the compiler cannot decide between constructing f using a reference to Foo or, as already mentioned, using a int* (obtained by way of copy-initializing) from the return value of operator int*. However, when the initializer expression is a temporary object, we also consider explicit conversions -- but only if they match a constructor taking a reference to Foo, our "possibly cv-qualified T", i.e. our copy and move constructors. This entire behavior is being consistent with [class.conv.fct¶2]:

    A conversion function may be explicit ([dcl.fct.spec]), in which case it is only considered as a user-defined conversion for direct-initialization ([dcl.init]). Otherwise, user-defined conversions are not restricted to use in assignments and initializations.

    And so, saying the same thing here for the 3rd time: if it isn't marked as explicit, there's nothing stopping the compiler from trying to copy-initialize an int* to be used for construction.

提交回复
热议问题