15

The following code compiles successfully with g++ 7.3.0 and fails to compile with clang++ 6.0.0 (compilation flags are -std=c++17 -Wall -Wextra -Werror -pedantic-errors):

auto foo = [](auto, auto... tail) {
    if constexpr (sizeof...(tail) > 0)
    {
        return foo(tail...);
    }
    else
    {
        return 42;
    }
};

int main()
{
}

clang++ compilation error message:

error: variable 'foo' declared with deduced type 'auto' cannot appear in its own initializer

return foo(tail...);

What behavior is standard compliant in this case?

einpoklum
  • 118,144
  • 57
  • 340
  • 684
Constructor
  • 7,273
  • 2
  • 24
  • 66
  • 2
    i don't see how it can compile because foo isn't captured (and can't be captured) – Tyker May 03 '18 at 13:35
  • 2
    @Tyker There is no need to capture global objects like `foo` in this example. – Constructor May 03 '18 at 13:38
  • 5
    The 2017 paper [p0839r0](http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0839r0.html) proposes a change to the C++ grammar to allow a self-referential name in a lambda's declaration. – Drew Dormann May 03 '18 at 13:42

1 Answers1

12

Clang is right to reject this according to [dcl.spec.auto]/10, as of C++17.

If the type of an entity with an undeduced placeholder type is needed to determine the type of an expression, the program is ill-formed.

The type of foo is needed to resolve the recursive call (find operator(), etc). It's needed to determine the closure type. Since the closure type is being deduced here... you see where it goes.

GCC may prove it's not always impossible to get around it, but in general the standard prohibits it.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458