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

Time:04-01

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".

  • Related