I stumbled on the following while trying to implement some SFINAE trickery (what I was actually trying to achieve is irrelevant; I wan't to understand this behavior):
I define a constexpr
function that takes a reference to an array of size 1, but I specify the array size through a lambda call:
constexpr bool f(const char(&)[ [](){return 1;}()]) {
return true;
}
(The
before the lambda is because the compiler complains about two consecutive left brackets.)
I add a caller function:
constexpr bool g() {
char x[1] = {};
return f(x);
}
This compiles fine.
Now I templatize and instantiate:
template<typename T>
constexpr bool f(const char(&)[ [](){return 1;}()]) {
return true;
}
constexpr bool g() {
char x[1] = {};
return f<int>(x);
}
This time I get a strange compiler error:
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.
Why am I getting this error?
The command I'm using is: /usr/lib/llvm-11/bin/clang -stdlib=libstdc -std=c 17 myprog.cc
The version info from the compiler is:
Debian clang version 11.1.0-4 build3
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/lib/llvm-11/bin
CodePudding user response:
Why am I getting this error?
/usr/lib/llvm-11/bin/clang -stdlib=libstdc -std=c 17 myprog.cc
Using lambdas in function signature isn't allowed in C 17:
[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 ]
The program is ill-formed. The diagnostic message has room for improvement. Not diagnosing the non-template is a compiler bug.
It's easy to work around using a constant. Much easier to read too:
constexpr inline auto s = [](){return 1;}();
template<typename T>
constexpr bool f(const char(&)[s])
Since proposal P0315, it should be allowed in C 20 because the highlighted part of the rule is removed. Clang however still fails to compile it in C 20 which is a bug as far as I can tell. At the moment, Clang's support for P0315 is listed as "partial".