Fed*_*dor 11 c++ templates language-lawyer c++-concepts c++20
在下面的程序中,函数foo接收v类型为 的参数std::integral_constant<bool, true>,该参数用于传入模板参数A<b>:
template <bool>
struct A{};
constexpr bool foo(auto b) {
return requires { typename A<b>; };
}
static_assert( foo( std::true_type{} ) );
Run Code Online (Sandbox Code Playgroud)
GCC 和 MSVC 都认为它有效(foo返回true),但在 Clang 中foo返回false。在线演示: https: //gcc.godbolt.org/z/j6Mnqjvbz
这里哪个编译器是正确的?
您提供的代码是正确的。由于已知的LLVM bug 42406/issue 41751,它失败了。
您可以对常量表达式中不存在的对象调用成员函数,只要成员函数不访问该对象即可。两个经典例子:
std::array<int, 10> arr; // arr is not usable in a constant expression,
// but we can obtain its size()
static_assert(arr.size() == 10);
std::true_type t;
static_assert(t); // does not access t, but calls its operator bool()
Run Code Online (Sandbox Code Playgroud)
Clang 编译了以上两者。相同的逻辑扩展到函数参数,这些参数在常量表达式中永远不可用:
// your code, except using std::true_type instead of auto
constexpr bool foo(std::true_type b) {
return requires { typename A<b>; };
}
Run Code Online (Sandbox Code Playgroud)
上面的代码应该可以工作,但会导致 clang 编译器错误:
Run Code Online (Sandbox Code Playgroud)error: reference to local variable 'b' declared in enclosing function > 'foo' 7 | return requires { typename A<b>; }; | ^ note: 'b' declared here 6 | constexpr bool foo(std::true_type b) { |
您的静态断言由于同样的原因而失败,尽管您在避免使用模板时可以更好地理解该问题。此错误消息显然是无意义的,并且是编译器错误,因为没有声明引用。