Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is a lambda expression a legal default (non-type template) argument?

All standard references below refers to N4861 (March 2020 post-Prague working draft/C++20 DIS).


Background

In the Q&A Are captureless lambdas structural types? it was made clear that certain lambda-expressions have associated closure types that are (literal and) structural types, such that a particular such closure type may be used as non-type template parameter; essentially passing structural type lambdas as non-type template parameters.

template<auto v>
constexpr auto identity_v = v;

constexpr auto l1 = [](){};
constexpr auto l2 = identity_v<l1>;

Now, according to [expr.prim.lambda.closure]/1 the type of each lambda-expression is unique

[...] a unique, unnamed non-union class type, called the closure type [...]

On the other hand, [basic.def.odr]/1 [extract, emphasis mine] states

No translation unit shall contain more than one definition of any variable, function, class type, enumeration type, template, default argument for a parameter (for a function in a given scope), or default template argument.

arguably meaning that default template arguments are considered definitions that need to respect the ODR.

Question

... which leads to my question:

  • Is a lambda expression a legal default (non-type template) argument and, if so, wouldn't this imply that each instantiation using such a default argument instantiates a unique specialization?

(Please highlight also if near-illegal: e.g. if anything beyond a single instantiation would lead to an ODR-violation).


Why?

If this is in fact legal, each invocation of say a variable template with a lambda as default argument would result in an instantiation of a unique specialization:

template<auto l = [](){}>
               // ^^^^^^ - lambda-expression as default argument
constexpr auto default_lambda = l;

static_assert(!std::is_same_v<
    decltype(default_lambda<>),
    decltype(default_lambda<>)>);

Both GCC (DEMO) and Clang (DEMO) accepts the program above

If the compilers are correct to accept this example, this means allowing another mechanism to capture and retrieve a meta-programming state, a technique that has since long been deemed, as per CWG open issue 2118, as

... arcane and should be made ill-formed.

like image 938
dfrib Avatar asked Oct 21 '20 13:10

dfrib


People also ask

What is non-type template argument?

A non-type template argument provided within a template argument list is an expression whose value can be determined at compile time. Such arguments must be constant expressions, addresses of functions or objects with external linkage, or addresses of static class members.

Can you template a lambda?

Lambda-expressions are not allowed in unevaluated expressions, template arguments, alias declarations, typedef declarations, and anywhere in a function (or function template) declaration except the function body and the function's default arguments.


1 Answers

Is a lambda expression a legal default (non-type template) argument and, if so, wouldn't this imply that each instantiation using such a default argument instantiates a unique specialization?

Yes, it means that given your templated variable:

template<auto l = [](){}>
constexpr auto default_lambda = l;

every call to default_lambda will produce a new template instantiation by generating a new unique closure type and thus provides a new way to capture a metaprogramming state.

Thus, every expressions that use default_lambda have to be reevaluated. If the state of the compiler changed since the last instantiation and if we used it in a dependent expression (ex: check that a type is defined) then the result of the expression might change. For example:

struct X; // not defined

template <typename T, auto = default_lambda<>>
consteval bool is_defined() {
    if constexpr (requires { T{}; }) {
        return true;
    } else {
        return false;
    }
}

static_assert(is_defined<X>() == false);

struct X {};
static_assert(is_defined<X>() == true);
like image 130
Mechap Avatar answered Oct 10 '22 09:10

Mechap