Why Does Not a Template Template Parameter Allow 'Typename' After the Parameter List

Why does not a template template parameter allow 'typename' after the parameter list

Short answer: because the Standard says so.

Longer answer: prior to Standardization, C++ templates required the class keyword for all template parameters. However, to stress the fact that templates could also be of non-class (i.e. builtin) type, an alternative keyword typename was introduced. However, in C++98, template-template parameters could only be of class-type, and this was the reason that the typename keyword was not added in that context.

Enter C++11 and its new feature template aliases, that now also introduced non-class templates, and hence non-class template-template parameters:

template<typename T> struct A {};
template<typename T> using B = int;

template<template<typename> class X> struct C;
C<A> ca; // ok
C<B> cb; // ok, not a class template
template<template<typename> typename X> struct D; // error, cannot use typename here

The above example was taken from the current C++1z proposal N4051 titled Allow typename in a template template parameter, and proposes to allow precisely that.

Clang 3.5 SVN now supports this with the -std=c++1z flag.

Why can't template functions be passed as a template template parameter?

I don't know for sure the answer to the question of why C++ does not provide function template template parameters, but I imagine it has something to do with:

  • Any nontrivial change to templates will require complicated analysis to determine what changes need to be made to the standard text
  • This feature would be rarely used; after all, class template template parameters are mostly used in partial specializations, i.e., to dispatch on types that are themselves template specializations, and it's rare to want to do that with functions
  • It wouldn't make sense to support function template template parameters without also supporting a type of template parameter that would accept any non-template function (we can do this in C++17 with auto but this is obviously way too late for C++98 to have function template template parameters)
  • You can work around the lack of function template template parameters using class templates anyway (sort of like what we do with partial specializations).
  • Function overloading complicates things. In the presence of overloading, there's no way to unambiguously name a particular function template. Should one be provided? Or, do we take the point of view that an overload set is meant to be passed as a whole to a function template template parameter? What if overload resolution then selects a non-template overload? How do we even answer these design questions without having a compelling use case?

If you believe that you know how to address all these concerns, and in particular can provide a compelling argument for why we need this feature in the language despite the fact that it would be complicated and we can work around its absence using class template template parameters, feel free to write up a proposal for the standard.

Why aren't typename template parameters implicitly recognized as types?

Parameter names aren't part of the entity that's being declared. This is true for both functions and templates. The following code only declares two separate entities:

extern void f(int, char, bool);
extern void f(int a, char b, bool c);
extern void f(int x, char b, bool z);

template <typename> struct X;
template <typename A> struct X;
template <typename T> struct X;

Note in particular that the following code is perfectly fine:

template <typename T> struct X { void f(); };   // X<T>::f not yet defined
template <typename U> void X<U>::f() {} // now it's defined

All attempts at deriving additional structure from parameter names must deal with this situation. One of the most popular requests in this area are named function parameters; to date there has not been a satisfactory proposal for such an extension.

To some extent, all such proposals would require making the parameter names part of the declared entity. For functions, for example, that would raise the question whether parameter names would need to be mangled and exposed to the linker.

Forward declare typename in template parameter list

One way is overloading:

template<auto First, auto Last, typename Container>
void doSomething(const Container& containter);

template<auto First, typename Container>
void doSomething(const Container& containter) {
doSomething<First, Container::size()>(containter);
}

template<typename Container>
void doSomething(const Container& containter) {
doSomething<0, Container::size()>(containter);
}

Why does std::stack not use template template parameter?

Because typically containers like std::vector have more than one template argument. By not caring about it being a template, you allow every kind of container to be used.

How would

template<class T, class Allocator = std::allocator<T>> class vector;

fit onto

template<typename> class Container

as you would have it in your stack? (Hint: it doesn't!) You'd need special cases for each number and kind of template arguments (type vs. non-type) you'd want to support, which is silly, because these typically don't contribute any more information than a simple

typename Container

Note that to get at the actual template arguments of e.g. a std::vector, you have the typedefs std::vector::value_type and std::vector::allocator_type, removing the need of having these types available explicitly where you actually use the type (i.e. the Container of stack).

Errors while using templates templates parameters

You're declaring template template parameter incorrectly. Change

template<class type, template<type> class T>
class stack

to

template<class type, template<typename> class T>
class stack

BTW: std::list has two template parameters (the 2nd one has default value), but T has only one; they don't match. Since C++17 it works fine but if your compiler doesn't support C++17 well you might have to use parameter pack to solve the issue.

template<class type, template<typename...> class T>
class stack

Can a type be defined inside a template parameter list in C++?

[temp.param]/2 says:

Types shall not be defined in a template-parameter declaration.

Taking this as written, GCC is correct to reject this code: this prohibition is not constrained to type-id of a type parameter, but applies to anywhere within template parameter declaration. Including nested within a lambda.

This sentence was added as a result of DR 1380 (N3481), which reveals it was considered already implied by what now I am guessing to be [dcl.fct]/17:

Types shall not be defined in return or parameter types.

This, however, only seems to apply to the type of the parameter declared and not to the initializer-clause.

On the other hand, one might also read it as prohibiting lambdas themselves in template parameters. After all, a lambda expression implicitly defines a class type ([expr.prim.lambda.closure]/1).

On the third hand, we also have [expr.prim.lambda.closure]/2, which states:

The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the corresponding lambda-expression.

The relevant scope here seems to be the namespace scope. This would imply the lambda should be treated as if its type were declared outside the template parameter list. But then, so should be declarations inside the body of the lambda, and the definition in the question should be allowed.

Personally, I consider it a defect in the standard that the scope of this prohibition seems so ill-defined.



Related Topics



Leave a reply



Submit