在 C++ 函数模板中,为什么我不能使用 lambda 来指定参数的数组大小?

In a C++ function template, why can't I use a lambda to specify the array size of a parameter?

我在尝试实现一些 SFINAE 技巧时偶然发现了以下内容(我实际上试图实现的是无关紧要的;我不想理解这种行为):

我定义了一个 constexpr 函数,它引用大小为 1 的数组,但我通过 lambda 调用指定数组大小:

constexpr bool f(const char(&)[+[](){return 1;}()]) {
  return true;
}

(lambda 之前的 + 是因为编译器抱怨两个连续的左括号。)

我添加调用函数:

constexpr bool g() {
  char x[1] = {};
  return f(x);
}

这编译得很好。

现在我模板化和实例化:

template<typename T>
constexpr bool f(const char(&)[+[](){return 1;}()]) {
  return true;
}

constexpr bool g() {
  char x[1] = {};
  return f<int>(x);
}

这次我得到一个奇怪的编译器错误:

ERROR: maps/suggest/indexer/nhr/nhr_flume_flags.cc:134:45 no matching function for call to 'f'
constexpr bool g() { char x[1] = {}; return f<int>(x); }
                                            ^~~~~~~
maps/suggest/indexer/nhr/nhr_flume_flags.cc:130:16 candidate function [with T = void] not viable: no known conversion from 'char[1]' to 'const char[+[]() {
    return 1;
}()]' for 1st argument
constexpr bool f(const char(&)[+[](){return 1;}()]) { return true; }
               ^
1 error generated.

为什么会出现此错误?

我使用的命令是:/usr/lib/llvm-11/bin/clang++ -stdlib=libstdc++ -std=c++17 myprog.cc

来自编译器的版本信息是:

Debian clang version 11.1.0-4+build3
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/lib/llvm-11/bin

Why am I getting this error?

/usr/lib/llvm-11/bin/clang++ -stdlib=libstdc++ -std=c++17 myprog.cc

C++17 不允许在函数签名中使用 lambda:

[expr.prim.lambda]

A lambda-expression is a prvalue whose result object is called the closure object. A lambda-expression shall not appear in an unevaluated operand, in a template-argument, in an alias-declaration, in a typedef declaration, or in the declaration of a function or function template outside its function body and default arguments. [ Note: The intention is to prevent lambdas from appearing in a signature.  — end note ] [ Note: A closure object behaves like a function object. — end note ]

节目是ill-formed。诊断消息有改进的余地。未诊断 non-template 是一个编译器错误。

使用常量很容易变通。也更容易阅读:

constexpr inline auto s = [](){return 1;}();

template<typename T>
constexpr bool f(const char(&)[s])

自提案 P0315 起,它应该在 C++20 中被允许,因为规则中突出显示的部分已被删除。然而,Clang 仍然无法在 C++20 中编译它,据我所知这是一个错误。目前,Clang 对 P0315 的支持被列为“部分”。