Constructor
Constructor

Reputation: 7483

Functor variadic template pack expansion for empty pack gives different results in clang++ and g++

The following code compiles successfully with clang++ 3.8.0 and fails to compile with g++ 7.2.0 (with the -std=c++14 -O0 -Wall -Wextra -Werror -pedantic-errors compilation flags):

auto foo = [](auto functor, auto... argument_functors)
{
    functor(argument_functors()...);
};

auto do_nothing = [](auto...) {};


int main()
{
    foo(do_nothing);
}

g++ error messages:

main.cpp: In instantiation of '<lambda(auto:1, auto:2 ...)> [with auto:1 = <lambda(auto:3, ...)>; auto:2 = {}]':
main.cpp:11:16:   required from here
main.cpp:3:9: error: no match for call to '(<lambda(auto:3, ...)>) ()'
  functor(argument_functors()...);
  ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:6:29: note: candidate: template<class auto:3> <lambda(auto:3, ...)>::operator decltype (((const<lambda(auto:3, ...)>*)((const<lambda(auto:3, ...)>* const)0))->operator()(static_cast<auto:3&&>(<anonymous>))) (*)(auto:3, ...)() const <deleted>
 auto do_nothing = [](auto...) {};
                             ^
main.cpp:6:29: note:   template argument deduction/substitution failed:
main.cpp:3:9: note:   candidate expects 1 argument, 0 provided
  functor(argument_functors()...);
  ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:6:29: note: candidate: template<class auto:3> <lambda(auto:3, ...)>
 auto do_nothing = [](auto...) {};
                             ^
main.cpp:6:29: note:   template argument deduction/substitution failed:
main.cpp:3:9: note:   candidate expects 1 argument, 0 provided
  functor(argument_functors()...);
  ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~

Which compiler behavior is standard compliant?

Upvotes: 3

Views: 185

Answers (1)

Barry
Barry

Reputation: 303487

This is gcc bug 64095.

From [dcl.fct]/18:

There is a syntactic ambiguity when an ellipsis occurs at the end of a parameter-declaration-clause without a preceding comma. In this case, the ellipsis is parsed as part of the abstract-declarator if the type of the parameter either names a template parameter pack that has not been expanded or contains auto; otherwise, it is parsed as part of the parameter-declaration-clause.

Basically, (T...) in a parameter list can be interpreted as either:

  • One unnamed parameter of type T, and an ellipsis.
  • A function parameter pack, with types of the template parameter pack T.

The disambiguation rule is supposed to prefer the latter if T is a template parameter pack or auto, but gcc is choosing to interpret this as an ellipsis parameter.

Upvotes: 7

Related Questions