Conversion operator template specialization

后端 未结 2 1571
天命终不由人
天命终不由人 2020-12-25 13:23

Here\'s a largely academic exercise in understanding conversion operators, templates and template specializations. The conversion operator template in the following code wo

相关标签:
2条回答
  • 2020-12-25 14:08

    static_cast here is equivalent of doing std::string(a).

    Note that std::string s = std::string(a); doesn't compile either. My guess is, there are plenty of overloads for the constructor, and the template version can convert a to many suitable types.

    On the other hand, with a fixed list of conversions, only one of those matches exactly a type that the string's constructor accepts.

    To test this, add a conversion to const char* - the non-templated version should start failing at the same place.

    (Now the question is why std::string s = a; works. Subtle differences between that and std::string s = std::string(a); are only known to gods.)

    0 讨论(0)
  • 2020-12-25 14:19

    You can reproduce the problem by just using

    std::string t(a);
    

    Combined with the actual error from GCC (error: call of overloaded 'basic_string(MyClass&)' is ambiguous) we have strong clues as to what may be happening: there is one preferred conversion sequence in the case of copy initialization (std::string s = a;), and in the case of direct initialization (std::string t(a); and static_cast) there are at least two sequences where one of them can't be preferred over the other.

    Looking at all the std::basic_string explicit constructors taking one argument (the only ones that would be considered during direct initialization but not copy initialization), we find explicit basic_string(const Allocator& a = Allocator()); which is in fact the only explicit constructor.

    Unfortunately I can't do much beyond that diagnostic: I can't think of a trick to discover is operator std::allocator<char> is instantiated or not (I tried SFINAE and operator std::allocator<char>() = delete;, to no success), and I know too little about function template specializations, overload resolution and library requirements to know if the behaviour of GCC is conforming or not.

    Since you say the exercise is academic, I will spare you the usual diatribe how non-explicit conversion operators are not a good idea. I think your code is a good enough example as to why anyway :)


    I got SFINAE to work. If the operator is declared as:

    template <
        typename T
        , typename Decayed = typename std::decay<T>::type
        , typename = typename std::enable_if<
            !std::is_same<
                const char*
                , Decayed
            >::value
            && !std::is_same<
                std::allocator<char>
                , Decayed
            >::value
            && !std::is_same<
                std::initializer_list<char>
                , Decayed
            >::value
        >::type
    >
    operator T();
    

    Then there is no ambiguity and the code will compile, the specialization for std::string will be picked and the resulting program will behave as desired. I still don't have an explanation as to why copy initialization is fine.

    0 讨论(0)
提交回复
热议问题