【问题标题】:MSVC std::pair implementation: is SFINAE applied correctly here?MSVC std::pair implementation:SFINAE 是否在这里正确应用?
【发布时间】:2018-06-22 08:24:04
【问题描述】:

考虑下面的std::pair 默认构造函数代码,来自Microsoft Visual Studio 15.4.5 附带的STL 实现:

template<class _Uty1 = _Ty1,
    class _Uty2 = _Ty2,
    class = enable_if_t<is_default_constructible<_Uty1>::value
                    && is_default_constructible<_Uty2>::value>>
    constexpr pair()
    : first(), second()
    {   // default construct
    }

我设置了/std:c++latest 选项,所以,根据标准(我在这里使用草案n4659)我希望如果_Ty1 或@,这个构造函数将被排除在重载决议之外987654326@ 不是默认可构造的:

23.4.2 类模板对[pairs.pair]

显式常量表达式对();

效果:值初始化第一个和第二个。

备注:此构造函数不得参与重载决议 除非is_default_constructible_v&lt;first_type&gt; 为真并且 is_default_constructible_v&lt;second_type&gt; 是真的。 [注:此行为 可以通过带有默认模板的构造函数模板来实现 论据。]

在上面的实现中,排除的执行如下:

class = enable_if_t<is_default_constructible<_Uty1>::value
                    && is_default_constructible<_Uty2>::value>

据我所知,SFINAE does not work 为模板类型参数默认值。

有趣的是,在 Microsoft Visual Studio 15.5.3 中,构造函数已更改为“正确版本”(“正确”基于我有限的模板知识):

template<class _Uty1 = _Ty1,
    class _Uty2 = _Ty2,
    enable_if_t<conjunction_v<
        is_default_constructible<_Uty1>,
        is_default_constructible<_Uty2>
    >, int> = 0>
    constexpr pair()
    : first(), second()
    {   // default construct
    }

所以我想知道第一个实现是否正确,如果正确,将其更改为第二个有什么意义。

【问题讨论】:

  • 模板类型参数的默认值只有在您有多个仅在默认值不同的重载时才会出现问题,因为默认值不参与重载解析。

标签: c++ templates stl


【解决方案1】:

并不是说 SFINAE 在默认模板参数中不起作用;只是它们不算作签名的一部分,因此将 SFINAE 机器放在那里意味着如果要构建重载集,则必须以其他方式使签名不同。

因此,这很好:

template<class T, class=std::enable_if_t<std::is_integral_v<T>>>
T meow();

template<class T, class=std::enable_if_t<!std::is_integral_v<T>>>
void meow();

因为签名不同(返回类型是函数模板签名的一部分——但不是函数);也是这样:

template<class T, class=std::enable_if_t<std::is_integral_v<T>>>
void meow(T);

template<class T, class=std::enable_if_t<!std::is_integral_v<T>>>
void meow(const T&);

但这不是(它重新声明了相同的函数模板,因此尝试为相同的模板参数提供两次默认模板参数):

template<class T, class=std::enable_if_t<std::is_integral_v<T>>>
void meow(const T&);

template<class T, class=std::enable_if_t<!std::is_integral_v<T>>>
void meow(const T&);

特别是关于 pair 构造函数模板,如果不知道其他构造函数模板是什么,您就无法真正判断它是否正确。也就是说,如果他们弄错了,我会感到非常惊讶。任何问题都应该可以通过简单的单元测试轻松发现。

【讨论】:

  • 啊,我明白了!问题是我从来没有仔细阅读过链接的问题,尽管它也给出了解释。
【解决方案2】:

我认为他们都是对的,但第二个更灵活。

【讨论】:

  • 您认为,但不完全确定?
【解决方案3】:

我相信这是正确的,因为使用 SFINAE 的目的是确保构造函数仅在元素可默认构造时可用,并且不允许选择所述构造函数的不同重载。

根据定义,只有一个版本的构造函数(或任何其他函数)接受 0 个参数,因此重载决议在这里不是问题。

【讨论】:

    猜你喜欢
    • 2011-02-18
    • 1970-01-01
    • 2023-02-16
    • 2023-02-09
    • 2015-09-25
    • 1970-01-01
    • 2021-11-18
    • 2010-09-11
    • 1970-01-01
    相关资源
    最近更新 更多