首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么“is_convertible”出现在<utility> std::<utility> (STL)中?

为什么“is_convertible”出现在<utility> std::<utility> (STL)中?
EN

Stack Overflow用户
提问于 2017-09-18 06:01:24
回答 2查看 298关注 0票数 7
代码语言:javascript
复制
    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::的构造函数,我们使用Other1和Other2来初始化 "first“和"second",

我认为is_constructible已经足够了,我们为什么在这里使用is_convertible?

顺便说一句,class = enable_if_t< ... ::value>enable_if_t< ... ::value,int> = 0有什么区别?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-09-18 19:51:14

我认为is_constructible已经足够了,我们为什么在这里使用is_convertible

这里的目标是正确处理explicit构造。考虑做前者并尝试编写一个包装器(在这里使用REQUIRES来隐藏任何您想要的SFINAE方法):

代码语言:javascript
复制
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;
};

如果我们只有这些,那么:

代码语言:javascript
复制
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的期望!

现在,如果s_constructible<T, U&&>是一个有效的表达式,那么如果可以从U&&中直接初始化T(std::declval<U&&>()),那么T(std::declval<U&&>())就是正确的。

另一方面,is_convertible<U&&, T>检查是否可以从T复制-初始化U&&。也就是说,如果T copy() { return std::declval<U&&>(); }是有效的。

不同之处在于,如果转换为explicit,则后者不能工作。

代码语言:javascript
复制
+-----+--------------------------+------------------------+
|     | is_constructible<T, int> | is_convertible<int, T> |
+-----+--------------------------+------------------------+
| Imp |        true_type         |       true_type        |
| Exp |        true_type         |       false_type       |
+-----+--------------------------+------------------------+

为了正确地传播外露性,我们需要同时使用这两个特征--并且我们可以利用它们来创建元特征:

代码语言:javascript
复制
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>;

这两个特性是不相交的,因此我们可以编写两个构造函数模板,它们肯定都不可行,其中一个构造函数是显式的,另一个构造函数不是:

代码语言:javascript
复制
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;
};

这给了我们想要的行为:

代码语言:javascript
复制
wrapper<Imp> wi = 0; // okay, calls non-explicit ctor
wrapper<Exp> we = 0; // error
wrapper<Exp> we2(0); // ok

这就是实现在这里所做的--除了两个元特征之外,它们拥有所有的条件-- explicitly。

票数 9
EN

Stack Overflow用户

发布于 2017-09-18 09:35:56

用于实现[pairs.pair]/12

除非is_­constructible_­v<first_­type, U1&&>为真,is_­constructible_­v<second_­type, U2&&>为真,否则此构造函数不应参与过载解析。构造函数是显式的当且仅当first­type>_ _is false or_ _is­convertible­v`为false时。

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46272501

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档