考虑一下这个小代码片段
namespace nsp
{
template<typename T>
concept Addable= requires(const T& a,const T& b)
{
{a + b} -> std::convertible_to<T>;
};
template<Addable T>
struct C
{
C();
};
}
template<nsp::Addable T>
nsp::C<T>::C() {};
如图所示,GCC(10.2(和clang(11.0(接受代码,而MSVC(x86 19.28(拒绝代码并返回错误消息:
error C3855: 'nsp::C<T>': template parameter 'T' is incompatible with the declaration.
这是MSVC的错误还是GCC和clang接受它是错误的?或者,我做了什么愚蠢的事吗?如果我将越界的定义移到名称空间nsp
中,它似乎也适用于MSVC。请参见此示例。
这种行为是MSVC中可观察到的偏差,通常在模板和SFINAE的上下文中可以看到。当声明不合格时(由于在同一命名空间中(,MSVC往往难以对具有限定条件的模板进行越界定义。我在处理SFINAE的形式时经常遇到这种情况,现在看来concept
s也会出现这种情况。
例如,MSVC拒绝有效代码:
namespace nsp {
template <typename T>
using is_convertible_to_bool = std::is_convertible<T, bool>;
template <typename T, std::enable_if_t<is_convertible_to_bool<T>::value,int> = 0>
void example(const T& x);
} // namespace nsp
template <typename T, std::enable_if_t<nsp::is_convertible_to_bool<T>::value,int>>
void nsp::example(const T& x)
{
}
实时示例
但是,如果您在namespace nsp
:的is_convertible_to_bool
上添加资格,MSVC将接受相同的代码
template <typename T, std::enable_if_t<nsp::is_convertible_to_bool<T>::value,int> = 0>
// ^~~~~ fixes it
void example(const T& x);
实时示例
类似地,如果您更改struct C
的定义以包含完全限定的概念名称:,那么您的代码示例实际上是有效的
template<nsp::Addable T>
// ^~~~~
// Qualifying here fixes the failure in MSVC
struct C
{
C();
};
实时示例
我没有时间检查编译器正确的查找规则标准(如果没有其他答案,稍后会这样做(,但我的期望实际上是MSVC提供了不正确的行为。基本名称查找应该在两个定义中选择相同的类型,因此代码应该是格式良好的。