考虑以下 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
中的任何一个,这个构造函数将被排除在重载决议之外。或 _Ty1
不是默认可构造的:
23.4.2 Class template pair [pairs.pair]
EXPLICIT constexpr pair();
Effects: Value-initializes first and second.
Remarks: This constructor shall not participate in overload resolution unless
is_default_constructible_v<first_type>
is true andis_default_constructible_v<second_type>
is true. [ Note: This behavior can be implemented by a constructor template with default template arguments.]
在上面的实现中,排除是按如下方式执行的:
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
}
所以我想知道第一个实现是否正确,如果正确,将其更改为第二个有什么意义。
最佳答案
并不是说 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
构造函数模板,如果不知道其他构造函数模板是什么,您无法真正判断它是否正确。也就是说,如果他们弄错了,我会感到非常惊讶;任何问题都应该可以通过简单的单元测试轻松发现。
关于c++ - MSVC std::pair 实现:SFINAE 是否在此处正确应用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48233615/