为什么在<utility>std::p air(STL)中"is_convertible"?
Why 'is_convertible' here in <utility> std::pair (STL)?
template<class _Other1,
class _Other2,
class = enable_if_t<is_constructible<_Ty1, _Other1>::value
&& is_constructible<_Ty2, _Other2>::value>,
enable_if_t<is_convertible<_Other1, _Ty1>::value
&& is_convertible<_Other2, _Ty2>::value, int> = 0>
constexpr pair(pair<_Other1, _Other2>&& _Right)
_NOEXCEPT_OP((is_nothrow_constructible<_Ty1, _Other1>::value
&& is_nothrow_constructible<_Ty2, _Other2>::value))
: first(_STD forward<_Other1>(_Right.first)),
second(_STD forward<_Other2>(_Right.second))
{ // construct from moved compatible pair
}
template<class _Other1,
class _Other2,
class = enable_if_t<is_constructible<_Ty1, _Other1>::value
&& is_constructible<_Ty2, _Other2>::value>,
enable_if_t<!is_convertible<_Other1, _Ty1>::value
|| !is_convertible<_Other2, _Ty2>::value, int> = 0>
constexpr explicit pair(pair<_Other1, _Other2>&& _Right)
_NOEXCEPT_OP((is_nothrow_constructible<_Ty1, _Other1>::value
&& is_nothrow_constructible<_Ty2, _Other2>::value))
: first(_STD forward<_Other1>(_Right.first)),
second(_STD forward<_Other2>(_Right.second))
{ // construct from moved compatible pair
}
VS 2017 行 206 的实用程序文件, _Other1和_Other2是参数,这是std::p air的构造功能, 并且我们使用 Other1 和 Other2 来初始化"第一个"和"第二个",
我认为is_constructible就足够了,为什么我们在这里使用is_convertible?
顺便问一下,class = enable_if_t< ... ::value>
和enable_if_t< ... ::value,int> = 0
有什么区别?
is_constructible
就足够了,为什么我们在这里使用is_convertible
?
这里的目标是妥善处理explicit
建设。考虑只做前者并尝试编写一个包装器(在此处使用REQUIRES
来隐藏您想要的SFINAE的任何方法):
template <class T>
class wrapper {
public:
template <class U, REQUIRES(std::is_constructible<T, U&&>::value)>
wrapper(U&& u) : val(std::forward<U>(u)) { }
private:
T val;
};
如果这就是我们所拥有的一切,那么:
struct Imp { Imp(int ); };
struct Exp { explicit Exp(int ); };
Imp i = 0; // ok
Exp e = 0; // error
wrapper<Imp> wi = 0; // ok
wrapper<Exp> we = 0; // ok?!?
我们绝对不希望最后一个没问题 - 这打破了对Exp
的期望!
现在,如果可以从U&&
直接初始化T
,则s_constructible<T, U&&>
为真 - 如果T(std::declval<U&&>())
是有效的表达式。
另一方面,is_convertible<U&&, T>
检查是否可以从U&&
复制初始化T
。也就是说,如果T copy() { return std::declval<U&&>(); }
有效。
不同之处在于,如果转换explicit
,后者不起作用:
+-----+--------------------------+------------------------+
| | is_constructible<T, int> | is_convertible<int, T> |
+-----+--------------------------+------------------------+
| Imp | true_type | true_type |
| Exp | true_type | false_type |
+-----+--------------------------+------------------------+
为了正确地传播显式性,我们需要同时使用这两个特征 - 我们可以从中创建元特征:
template <class T, class From>
using is_explicitly_constructible = std::integral_constant<bool,
std::is_constructible<T, From>::value &&
!std::is_convertible<From, T>::value>;
template <class T, class From>
using is_implicitly_constructible = std::integral_constant<bool,
std::is_constructible<T, From>::value &&
std::is_convertible<From, T>::value>;
这两个特征是不相交的,因此我们可以编写两个绝对不可行的构造函数模板,其中一个构造函数是显式的,另一个不是:
template <class T>
class wrapper {
public:
template <class U, REQUIRES(is_explicitly_constructible<T, U&&>::value)>
explicit wrapper(U&& u) : val(std::forward<U>(u)) { }
template <class U, REQUIRES(is_implicitly_constructible<T, U&&>::value)>
wrapper(U&& u) : val(std::forward<U>(u)) { }
private:
T val;
};
这为我们提供了所需的行为:
wrapper<Imp> wi = 0; // okay, calls non-explicit ctor
wrapper<Exp> we = 0; // error
wrapper<Exp> we2(0); // ok
这就是实现在这里所做的 - 除了不是两个元特征,而是将所有条件写explicit
ly。
对于实现 [pairs.pair]/12:
此构造函数不应参与重载解析,除非
is_constructible_v<first_type, U1&&>
为 true,并且is_constructible_v<second_type, U2&&>
是真的。构造函数是显式的,当且仅当is_convertible_v<U1&&, first_type>
为假或is_convertible_v<U2&&, second_type>
是错误的。
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 在C应用程序中运行C++(带有STL)函数
- 使用2个键的cpp-stl::优先级队列排序不正确
- 在STL容器中使用模板类
- 用C++中的CPerson(类)类型的对象初始化STL矢量
- 将stl字符串缩小到小于15个字符的容量
- 在为LINUX创建共享库时,如何避免STL的私有/弱副本
- 检查函数返回类型是否与STL容器类型值相同
- STL算法函数在多个一维容器上的使用
- 在STL - C++中按成绩对学生列表进行排序?
- 为什么 STL 容器适配器堆栈中的 top 返回常量引用?
- λ可以适应STL吗?
- 为什么使用 NDK 不能存在不同的 stl 实现?
- 如果我真的真的想从 STL 容器继承,并且我继承构造函数并删除新运算符,会发生什么?
- 使用 char 分隔符解析C++中的字符串,但将可重复的字符保留为每个解析的子字符串 (C++ STL) 中的分隔符
- 在C++中迭代 STL 集时出现奇怪的问题<CStudent>
- 如何在 C++17 STL 并行算法中处理调度?
- 在学习数据结构之前对STL有一个了解是好的吗?
- C++ STL 排序会检查 NaN 吗?