函数参数可以用作模板参数吗?

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

这里哪个编译器是正确的?

Jan*_*tke 2

您提供的代码是正确的。由于已知的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 编译器错误:

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

您的静态断言由于同样的原因而失败,尽管您在避免使用模板时可以更好地理解该问题。此错误消息显然是无意义的,并且是编译器错误,因为没有声明引用。

  • 事情变得更奇怪了。这是被接受的(保留所有有问题的代码并仅替换 `foo`): `constexpr bool foo(auto b) { std::true_type x{}; 返回需要 { 类型名 A&lt;x&gt;; }; }` 但是 `constexpr bool foo() { std::true_type x{}; 返回需要 { 类型名 A&lt;x&gt;; }; }` 失败 (2认同)