SFINAE 条件和构造函数参数类型
SFINAE conditional and constructor argument types
我遇到了以下允许围绕 T
构造包装器对象的技术,但是从 U
类型的对象,如果 T
可以从 [=12= 构造]:
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,is_constructible
测试中使用的类型U
可以不同于arg
.
的cv限定类型
尽管表达式 value(arg)
有效,但 SFINAE 测试是否有可能失败?
Is it possible that the SFINAE test could fail although the expression value(arg) is valid?
你写的方式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
)类型右值引用的变量的左值引用作为 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
实际转发具有正确类型的参数。
这至少解决了上面提到的问题,它应该给你你正在寻找的保证。
我遇到了以下允许围绕 T
构造包装器对象的技术,但是从 U
类型的对象,如果 T
可以从 [=12= 构造]:
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,is_constructible
测试中使用的类型U
可以不同于arg
.
的cv限定类型
尽管表达式 value(arg)
有效,但 SFINAE 测试是否有可能失败?
Is it possible that the SFINAE test could fail although the expression value(arg) is valid?
你写的方式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
)类型右值引用的变量的左值引用作为 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
实际转发具有正确类型的参数。
这至少解决了上面提到的问题,它应该给你你正在寻找的保证。