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
C++ Cannot Convert from Base a to Derived Type B via Virtual Base A
Are C/C++ Fundamental Types Atomic
How to Pan Images in Qgraphicsview
C++ Frontend Only Compiler (Convert C++ to C)
Qt "Private Slots:" What Is This
What Does 'Value Initializing' Something Mean
Code Browsing, Refactoring, Auto Completion in Emacs
How to Read Jpeg and Png Pixels in C++ on Linux
Portability of Native C++ Properties
How to Check If Given Int Exists in Array
Get Local Ip-Address Using Boost.Asio
How to Use Capturestackbacktrace to Capture the Exception Stack, Not the Calling Stack
How Can Boost::Serialization Be Used with Std::Shared_Ptr from C++11
C++ Tips for Code Optimization on Arm Devices