c ++模板类型推导在强制转换运算符中失败

Tms*_*tel 8 c++ templates casting template-meta-programming type-deduction

我把这个问题简化了一些:

http://coliru.stacked-crooked.com/a/2660b33492651e92

#include <iostream>
#include <string>
#include <type_traits>

template<typename C>
struct get_type
{
    C operator()() const = delete;
};

template<>
struct get_type<std::string>
{
    std::string operator()() const { return "asd"; }
};

template<>
struct get_type<size_t> {
    size_t operator()() const { return 6; }
};

struct S
{
    S(){}
    template<typename T>
    operator T() { return get_type<T>{}(); }
};

struct A
{
    A() :s{S{}}, n{S{}} {}
    std::string s;
    size_t n;
};

int main()
{
    A a;
    std::cout << "Spock out." << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

这会生成以下错误:

'In instantiation of 'S::operator T() [with T = char]':'...
Run Code Online (Sandbox Code Playgroud)

为什么T被推导为char而不是std :: string?

编辑:

@ YSC的答案似乎是正确的:https: //stackoverflow.com/a/46608866/4723722

我编辑了帖子以添加解决方案:http: //coliru.stacked-crooked.com/a/06d31d981acd2544

struct S
{
    S(){}
    template<typename T>
    explicit operator T() { return get_type<T>{}(); }
};
Run Code Online (Sandbox Code Playgroud)

YSC*_*YSC 6

这里:

A() : s( S{} ), ...
Run Code Online (Sandbox Code Playgroud)

建设A::s从一个S实例是不明确的,因为每一种类型T的女巫std::is_constructible<std::string, T>,模板函数S::operator T()是从可能的转换路径S,以T对std::string.

它通过使用T= 进行测试来接缝您的GCC版本char.clang列出多个候选人:http://coliru.stacked-crooked.com/a/17e247cca8b79c77:

/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/basic_string.h:413:7: note: candidate constructor
      basic_string(const _Alloc& __a) _GLIBCXX_NOEXCEPT
      ^
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/basic_string.h:421:7: note: candidate constructor
      basic_string(const basic_string& __str)
      ^
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/basic_string.h:493:7: note: candidate constructor
      basic_string(const _CharT* __s, const _Alloc& __a = _Alloc())
      ^
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/basic_string.h:515:7: note: candidate constructor
      basic_string(basic_string&& __str) noexcept
      ^
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/basic_string.h:542:7: note: candidate constructor
      basic_string(initializer_list<_CharT> __l, const _Alloc& __a = _Alloc())
Run Code Online (Sandbox Code Playgroud)

作为自己发现的OP,使转换运算符S explicit解决了歧义(demo):

struct S
{
    S(){}
    template<typename T>
    explicit operator T() { return get_type<T>{}(); }
};
Run Code Online (Sandbox Code Playgroud)

这是有效的(正如用户AndyG发现的那样)因为在[over.match.copy]下可以读到:

初始化临时绑定到构造函数的第一个参数时,其中参数的类型为"引用可能的cv-qualified T",并且在直接初始化类型的对象的上下文中使用单个参数调用构造函数"cv2 T",也考虑了显式转换函数.

  • omg你是对的http://coliru.stacked-crooked.com/a/06d31d981acd2544如果我让运算符T显式,它编译 (2认同)