MSVC std :: pair实现:SFINAE在这里正确应用了吗?

Edg*_*jān 4 c++ templates stl

请考虑以下Microsoft Visual Studio 15.4.5附带std::pairSTL实现中的默认构造函数代码:

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
    }
Run Code Online (Sandbox Code Playgroud)

我设置/std:c++latest选项,所以,根据标准(我在这里使用草案n4659)我期望这个构造函数将被排除在重载决议之外,如果其中一个_Ty1_Ty1不是默认构造:

23.4.2类模板对[pairs.pair]

EXPLICIT constexpr pair();

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

备注:除非is_default_constructible_v<first_type>为true且 is_default_constructible_v<second_type>为true,否则此构造函数不应参与重载决策.[注意:此行为可以通过带有默认模板参数的构造函数模板实现.

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

class = enable_if_t<is_default_constructible<_Uty1>::value
                    && is_default_constructible<_Uty2>::value>
Run Code Online (Sandbox Code Playgroud)

据我所知,SFINAE 不适用于模板类型参数默认值.

有趣的是,在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
    }
Run Code Online (Sandbox Code Playgroud)

所以我想知道第一个实现是否正确,如果它是正确的,那么将它改为第二个是什么意思.

T.C*_*.C. 7

这并不是说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();
Run Code Online (Sandbox Code Playgroud)

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

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&);
Run Code Online (Sandbox Code Playgroud)

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

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&);
Run Code Online (Sandbox Code Playgroud)

pair特别是对于那个构造函数模板,如果不知道其他构造函数模板是什么,就无法确定它是否正确.也就是说,如果他们弄错了,我会非常惊讶; 任何问题都应该通过简单的单元测试轻松捕获.