C++20 概念:外线定义在 MSVC 中失败,但在 GCC 或 clang 中没有
C++20 Concepts: out-of-line-definition fails with MSVC but not in GCC or clang
考虑这个小代码片段
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() {};
如图所示here 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。看到这个 example.
此行为是 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)
{
}
但是,MSVC 将接受相同的代码,前提是您在 is_convertible_to_bool
上添加限定条件 from namespace nsp
:
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 提供 不正确 行为。基本名称查找在两个定义中应该 select 相同的类型,因此代码 应该 格式正确。
考虑这个小代码片段
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() {};
如图所示here 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。看到这个 example.
此行为是 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)
{
}
但是,MSVC 将接受相同的代码,前提是您在 is_convertible_to_bool
上添加限定条件 from namespace nsp
:
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 提供 不正确 行为。基本名称查找在两个定义中应该 select 相同的类型,因此代码 应该 格式正确。