代码之家  ›  专栏  ›  技术社区  ›  Pietro Saccardi

如果T可转换为U,则将类<T>转换为类<U>

  •  2
  • Pietro Saccardi  · 技术社区  · 8 年前

    我想创建一个模板化类 test<T> 我可以转换成 test<U> (可能隐含)如果 T 可转换为 U 测试<U(>); ,其中模板参数 U 由控制 enable_if .

    #include <iostream>
    #include <type_traits>
    
    template <typename T>
    class test {
        int _foo;
    public:
        int foo() const { return _foo; }
    
        test() : _foo(5) {}
    
        // This works:
    
        // template <typename U>
        // test(test<U> other)
        // : _foo(other.foo()) {}
    
        // This doesn't, can't resolve `U`:
    
        template <typename U>
        test(test<typename std::enable_if<std::is_convertible<U, T>::value, U>::type> other)
        : _foo(other.foo()) {}
    
    };
    
    int main() {
        test<int> a;
        test<long> b = a; // T = long, U = int
    
        // true
        std::cout << std::boolalpha << std::is_convertible<int, long>::value << std::endl;
    
        return 0;
    }
    

    如果我只声明第一个模板化构造函数,代码就可以正常工作。使用第二个构造函数,它不会编译:

    21:9: note: candidate template ignored: couldn't infer template argument 'U'
        test(test<typename std::enable_if<std::is_convertible<U, T>::value, U>::type> other)
        ^
    

    为什么编译器不能推断 U 在这种情况下? 最好的制作方法是什么 测试<T> 可转换为 测试<U(>); ?


    顺便说一句,我通过将 测试<T> 友元,并声明一个转换运算符,该运算符使用 启用_if (如下),但我仍然想知道为什么第一种更简单的方法不起作用。

    template <typename T>
    class test {
        int _foo;
    
        template <typename U>
        friend class test;
    
        test(int foo) : _foo(foo) {}
    
    public:
        int foo() const { return _foo; }
    
        test() : _foo(5) {}
    
        template <typename U>
        operator test<U>() const {
            using return_t = typename std::enable_if<std::is_convertible<U, T>::value, U>::type;
            return test<return_t>(_foo);
        }
    };
    
    2 回复  |  直到 8 年前
        1
  •  3
  •   Community    7 年前

    U 出现在 non-deduced context .

    这样可以解决编译器错误:

    template <typename U, typename = typename std::enable_if<std::is_convertible<U, T>::value, U>::type>
    test(test<U> other)
    : _foo(other.foo()) {}
    

    live example

        2
  •  2
  •   user743382 user743382    8 年前

    为什么在这种情况下编译器不能推断U?

    类型演绎根本无法推断 T 来自参数类型,例如 a<T>::b .即使你有

    template <typename T> struct identity { typedef T type; };
    

    然后是编译器 不能排除你在某个地方提供偷偷制造的专业化服务 identity<X>::type Y 对于某些类型 X .

    这和 std::enable_if :标准库类模板在语言规则中没有得到特殊处理,因此编译器无法确定如果 std::enable_if<cond, U>::type 应该是 十、 然后 U 必须是 十、 .

    这就是为什么对于常规函数, 标准::启用if 通常出现在返回类型中。它不能在参数中,原因与构造函数相同。它不能在模板参数中,因为调用者可以指定不同的类型并绕过您的限制。但返回类型是安全的。

    标准::启用if 在模板中,m.s.已经回答的默认参数在那里是安全的。