如果 T 可转换为 U,则将 class<T> 转换为 class<U>
Convert class<T> to class<U> if T is convertible to U
我想创建一个模板化的 class test<T>
,如果 T
可转换为 U
,我可以将其转换为 test<U>
(可能是隐含的) .我想到的最简单的想法是添加一个采用 test<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
? 看起来很简单,我一定是在模板推导中遗漏了一些东西。此外,如果无法通过这种方式实现转换,将 test<T>
转换为 test<U>
的最佳方法是什么?
作为旁注,我设法通过让所有 test<T>
成为朋友,并声明一个在实现中使用 enable_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);
}
};
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()) {}
Why can't the compiler infer U in this case?
类型推导根本无法从 a<T>::b
等参数类型推断出 T
。即使你有
template <typename T> struct identity { typedef T type; };
那么编译器 仍然 不能排除你在某个地方提供了一个专门化的地方,偷偷地为某种类型 X
identity<X>::type
Y
。
与std::enable_if
相同:标准库class模板在语言规则中没有得到特殊处理,所以编译器无法判断std::enable_if<cond, U>::type
是否应该是 X
,那么 U
必须是 X
。
这就是为什么对于常规函数,std::enable_if
通常出现在 return 类型中。它不能在参数中,原因与构造函数相同。它不能在模板参数中,因为调用者可以指定不同的类型并绕过您的限制。但是 return 类型是安全的。
构造函数没有 return 类型。幸运的是,调用者不能显式指定构造函数模板参数,因此将 std::enable_if
放入模板默认参数中,正如 m.s 已经回答的那样。那里很安全。
我想创建一个模板化的 class test<T>
,如果 T
可转换为 U
,我可以将其转换为 test<U>
(可能是隐含的) .我想到的最简单的想法是添加一个采用 test<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
? 看起来很简单,我一定是在模板推导中遗漏了一些东西。此外,如果无法通过这种方式实现转换,将 test<T>
转换为 test<U>
的最佳方法是什么?
作为旁注,我设法通过让所有 test<T>
成为朋友,并声明一个在实现中使用 enable_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);
}
};
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()) {}
Why can't the compiler infer U in this case?
类型推导根本无法从 a<T>::b
等参数类型推断出 T
。即使你有
template <typename T> struct identity { typedef T type; };
那么编译器 仍然 不能排除你在某个地方提供了一个专门化的地方,偷偷地为某种类型 X
identity<X>::type
Y
。
与std::enable_if
相同:标准库class模板在语言规则中没有得到特殊处理,所以编译器无法判断std::enable_if<cond, U>::type
是否应该是 X
,那么 U
必须是 X
。
这就是为什么对于常规函数,std::enable_if
通常出现在 return 类型中。它不能在参数中,原因与构造函数相同。它不能在模板参数中,因为调用者可以指定不同的类型并绕过您的限制。但是 return 类型是安全的。
构造函数没有 return 类型。幸运的是,调用者不能显式指定构造函数模板参数,因此将 std::enable_if
放入模板默认参数中,正如 m.s 已经回答的那样。那里很安全。