我遇到了以下允许在T
周围构建包装器对象的技术,但是从U
类型的对象构建,如果T
可以从U
构造:
template< typename T >
struct S {
template< typename U,
typename = std::enable_if_t<
std::is_constructible< T, U >::value > >
explicit S (U&& arg) : value (arg)
{ }
...
};
IIUC,U
测试中使用的is_constructible
类型可能与arg
的cv限定类型不同。
虽然表达式value(arg)
有效,但SFINAE测试是否可能失败?
答案 0 :(得分:4)
虽然表达式值(arg)有效,但SFINAE测试是否可能失败?
你写S
的方式:是的,这是可能的。
它遵循一个最小的(非)工作示例:
#include<type_traits>
template< typename T >
struct S {
template< typename U
, typename = std::enable_if_t<std::is_constructible< T, U >::value >
> explicit S (U&& arg) : value{arg} {}
T value;
};
struct A {};
struct B {
B(A &) {}
};
int main() {
S<B> s(A{});
}
上面的代码不能编译,但如果您注释掉以下行,它会编译:
, typename = std::enable_if_t<std::is_constructible< T, U >::value >
问题是您没有转发构造函数参数。相反,您正在使用对A
(arg
)的rvalue引用类型的变量的左值引用作为value
的参数。
B
不能从对A
的右值引用构造,并且sfinae表达式失败(正确),但实际上并没有使用这样的引用来构造参数,因此删除了它所使用的sfinae表达式。登记/>
实际上,B
可以从A
的左值引用构造,这就是您在编写value{arg}
时使用的内容。
你应该写下S
,如下所示:
#include<utility>
// ...
template< typename T >
struct S {
template< typename U
, typename = std::enable_if_t<std::is_constructible< T, U >::value >
> explicit S (U&& arg) : value (std::forward<U>(arg)) { }
T value;
};
请注意使用std::forward
实际转发具有正确类型的参数
这至少解决了上述问题,它应该为您提供所需的保证。