3

In we got auto template parameters. I was trying to use one to pass an object in this question: Can I Write Relational Operators in Terms of Arithmetic Operations? But directed by AndyG's comment I found that didn't compile :(

Given the template function:

template <auto T>
void foo()

There seem to be restrictions on what I can pass as a template parameter. For example, as seen in my linked question I cannot seem to pass functors:

foo<plus<int>{}>()

Is there a list somewhere of what is and isn't allowed?

Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • 1
    The same restrictions as without `auto` apply: https://stackoverflow.com/Questions/5687540/non-type-template-parameters Also see the comments to the top answer with regard to changes in upcoming C++20. –  Dec 13 '18 at 12:38
  • @AndyG I mean I'm worthless without auto-complete :J – Jonathan Mee Dec 14 '18 at 04:47

2 Answers2

3

I believe this is entirely handled by the following standard statement:

[temp.arg.nontype]
1: If the type T of a template-parameter ([temp.param]) contains a placeholder type ([dcl.spec.auto]) or a placeholder for a deduced class type ([dcl.type.class.deduct]), the type of the parameter is the type deduced for the variable x in the invented declaration

T x = template-argument ;

If a deduced parameter type is not permitted for a template-parameter declaration ([temp.param]), the program is ill-formed.

Passing functor types is allowed. Passing a functor instance is not, just like passing an instance of struct A {}; is not.

As for what non-type template parameters are allowed:

4: A non-type template-parameter shall have one of the following (optionally cv-qualified) types:

(4.1) a type that is literal, has strong structural equality ([class.compare.default]), has no mutable or volatile subobjects, and in which if there is a defaulted member operator<=>, then it is declared public,

(4.2) an lvalue reference type,

(4.3) a type that contains a placeholder type ([dcl.spec.auto]), or

(4.4) a placeholder for a deduced class type ([dcl.type.class.deduct]).

5: [ Note: Other types are disallowed either explicitly below or implicitly by the rules governing the form of template-arguments ([temp.arg]). — end note  ] The top-level cv-qualifiers on the template-parameter are ignored when determining its type.

Max Langhof
  • 23,383
  • 5
  • 39
  • 72
  • So... is there a list somewhere of what "is not permitted for a template-parameter declaration?" I guess that's the answer to my question. – Jonathan Mee Dec 13 '18 at 12:38
2

In C++17, the restriction can be found in [temp.param]/4:

A non-type template-parameter shall have one of the following (optionally cv-qualified) types:

  • integral or enumeration type,
  • pointer to object or pointer to function,
  • lvalue reference to object or lvalue reference to function,
  • pointer to member,
  • std​::​nullptr_­t, or
  • a type that contains a placeholder type.

with additional restrictions on the arguments in [temp.arg.nontype]/2:

For a non-type template-parameter of reference or pointer type, the value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):

  • a subobject,
  • a temporary object,
  • a string literal,
  • the result of a typeid expression, or
  • a predefined _­_­func_­_­ variable.

Where you're going wrong is that std::plus<int> is not a valid non-type template parameter. It is none of those things in that first list.


In C++20, the kinds of types you can use as non-type template parameters will be greatly expanded. We will be able to use class types as non-type template parameters, provided those class types satisfy something called "strong structural equality." In the current draft, that is defined in terms of public, defaulted operator<=>. In P1185, currently in flight and likely to be adopted, it will change slightly to be defined in terms of public, defaulted operator==.

But even in C++20, std::plus<int> does not actually define any comparison operators - so you still would not be able to use it as a non-type template parameter.

Barry
  • 286,269
  • 29
  • 621
  • 977