In the C++14 draft standard, [temp.param]/11 says:
If a template-parameter of a primary class template or alias template
is a template parameter pack, it shall be the last template-parameter.
If you try compiling the following template, then the compiler will complain.
template< typename ...Args, void(*f)(Args...) > // ERROR
struct Bar
{};
But how does it work in this case?
template< typename F, F >
struct Bar;
template< typename ...Args, void(*f)(Args...) > // OK ???
struct Bar< void(*)(Args...), f >
{};
I can see that it has something to do with it being part of the specialization class template, but why?
The rule clearly states that it applies to a primary class template. Does this mean that the rules change for specializations?
I tried to search for this in the standard, but couldn't find anything. Can you please shine some light into this.
The rule clearly states that it applies to a primary class template. Does this mean that the rules change for specializations?
Yes. Quite simply because a specialization is not a primary class template. So if the wording was intended to apply to all template declarations, it would say so. Instead, the rule is very much intended to only apply to the primary class template (... and alias templates, which cannot be specialized). There is no such restriction for specializations.
This is fundamentally because it is not possible to provide any template arguments after a template parameter pack in the primary template, but it is definitely possible to do so in specializations. For instance, here's one way to concatenate two tuple specializations:
template <typename T, typename U>
struct tuple_concat;
template <typename... Ts, typename... Us> // <== parameter pack *after* parameter pack
struct tuple_concat<tuple<Ts...>, tuple<Us...>> {
using type = tuple<Ts..., Us...>;
};
This is fine, it works, it's useful. But there's no benefit† from being able to write stuff like this in a primary class/variable/alias template - so it's forbidden for simplicity.
†As with all things C++, there is of course a footnote. You could have been able to provide a trailing defaulted template parameter that is used to trigger a substitution failure. But there are other ways you can go about solving that problem, and then we'll have Concepts soon anyway.
Related
I try to create template alias which cannot be distinguished from original.
So, I create traits to check when 2 templates (not types) are equal:
template <template <class...> class C1,
template <class...> class C2>
struct is_same_template : std::false_type {};
template <template <class...> class C1>
struct is_same_template<C1, C1> : std::true_type {};
Now test it:
// Expected alias
template <typename ... Ts> using V_Ts = std::vector<Ts...>; // Variadic
// Fallback alias
template <typename T, typename A> using V = std::vector<T, A>; // Exact count
static_assert(!is_same_template<std::vector, V_Ts>::value); // Alias rejected by gcc/clang
static_assert( is_same_template<std::vector, V>::value); // Alias accepted only for gcc
Demo
Is it possible to create "true" alias?
which compiler is right?
I try to create template alias which cannot be distinguished from original.
I don't think this is currently possible. There are (unfortunately) no template aliases, there are only alias templates. And an alias template is always a template of its own [temp.alias]/1. A specialization of an alias template is equivalent to the type you get by substituting the template arguments into the alias template, but the alias template itself is not an alias for another template [temp.alias]/2. I would consider GCC letting your second static_assert pass a bug in GCC…
As pointed out by #HolyBlackCat in the comment above, there is a related question and answer which points to numerous related CWG issues. One issue in particular (CWG 1286) would seem to suggest that there is desire to allow an alias template to itself be equivalent to the template it refers to under certain circumstances. However, it does not seem that the proposed resolution has been adopted due to concerns raised later. The relevant wording in the current standard draft ([temp.alias] and [temp.type]) appears to be unchanged from C++11…
An allocator can optionally have nested types like pointer, const_pointer. But one can always use these interface with std::allocator_traits<Allocator>, which would provide a default version of these types if they are absent in Allocator.
How is std::allocator_traits implemented? How can a template choose a default version of nested type when it's absent?
The solution is to refer to the type T::pointer in a context where it does not cause an error if it is not a valid type, instead it causes template argument deduction to fail. The general form of this is known as SFINAE, which stands for "Substitution Failure Is Not An Error". For a explanation of how it works see my SFINAE Functionality Is Not Arcane Esoterica presentation.
There are various techniques, often involving overloaded function templates, but my current favourite uses the void_t idiom to select a partial specialization of a class template:
template<typename T>
using void_t = void;
template<typename T, typename = void>
struct get_pointer
{
using type = typename T::value_type*;
};
template<typename T>
struct get_pointer<T, void_t<typename T::pointer>>
{
using type = typename T::pointer;
};
Now given an allocator type A you can use typename get_pointer<A>::type to refer to A::pointer if that exists, otherwise A::value_type*
The code above works because when A::pointer is a valid type the partial specialization matches and is more specialized than the primary template, and so gets used. When A::pointer is not a valid type the partial specialization is ill-formed, so the primary template is used.
Template template typename?
When using template template syntax as in template <template <typename> class T>, it is required to use the keyword class, as using typename gives an error along the lines of:
error: template template parameter requires 'class' after the parameter list
Everywhere else the keywords typename and class are interchangeable in the basic case of declaring a template parameter.
You could argue that the requirement when using template template is a hint that you are expected to pass a class type, but this is not always the case (especially not after C++11 introduced templated type aliases).
template <template <typename> class T> // 'class' keyword required.
struct Foo {
using type = T<int>;
};
template <typename T>
using type = T (*)();
using func_ptr_t = Foo<type>::type;
What is the reasoning behind this?
Is there any specific reason as to why typename is not allowed in template template declarations?
Does the C++ standard say anything about this?
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.
I'm looking for the rational behind this restriction [...]
Before C++11 was introduced, the only templates you could pass to a template template parameter were class templates.
That's why the use of the keyword class was enforced.
Additionally, the keyword typename implies that the template parameter is a substitution for an arbitrary type and not a template, so using typename in that context would just blur the line between the names of types and (class) templates.
That's comprehensible.
Nowadays, such arguments can be the names of class templates or alias templates, and since those aren't even remotely connected, the enforcement of the keyword class is more or less obsolete. The proposal N4051 opts to change this with C++1Z.
Template template typename?
When using template template syntax as in template <template <typename> class T>, it is required to use the keyword class, as using typename gives an error along the lines of:
error: template template parameter requires 'class' after the parameter list
Everywhere else the keywords typename and class are interchangeable in the basic case of declaring a template parameter.
You could argue that the requirement when using template template is a hint that you are expected to pass a class type, but this is not always the case (especially not after C++11 introduced templated type aliases).
template <template <typename> class T> // 'class' keyword required.
struct Foo {
using type = T<int>;
};
template <typename T>
using type = T (*)();
using func_ptr_t = Foo<type>::type;
What is the reasoning behind this?
Is there any specific reason as to why typename is not allowed in template template declarations?
Does the C++ standard say anything about this?
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.
I'm looking for the rational behind this restriction [...]
Before C++11 was introduced, the only templates you could pass to a template template parameter were class templates.
That's why the use of the keyword class was enforced.
Additionally, the keyword typename implies that the template parameter is a substitution for an arbitrary type and not a template, so using typename in that context would just blur the line between the names of types and (class) templates.
That's comprehensible.
Nowadays, such arguments can be the names of class templates or alias templates, and since those aren't even remotely connected, the enforcement of the keyword class is more or less obsolete. The proposal N4051 opts to change this with C++1Z.
For templates I have seen both declarations:
template < typename T >
template < class T >
What's the difference?
And what exactly do those keywords mean in the following example (taken from the German Wikipedia article about templates)?
template < template < typename, typename > class Container, typename Type >
class Example
{
Container< Type, std::allocator < Type > > baz;
};
typename and class are interchangeable in the basic case of specifying a template:
template<class T>
class Foo
{
};
and
template<typename T>
class Foo
{
};
are equivalent.
Having said that, there are specific cases where there is a difference between typename and class.
The first one is in the case of dependent types. typename is used to declare when you are referencing a nested type that depends on another template parameter, such as the typedef in this example:
template<typename param_t>
class Foo
{
typedef typename param_t::baz sub_t;
};
The second one you actually show in your question, though you might not realize it:
template < template < typename, typename > class Container, typename Type >
When specifying a template template, the class keyword MUST be used as above -- it is not interchangeable with typename in this case (note: since C++17 both keywords are allowed in this case).
You also must use class when explicitly instantiating a template:
template class Foo<int>;
I'm sure that there are other cases that I've missed, but the bottom line is: these two keywords are not equivalent, and these are some common cases where you need to use one or the other.
For naming template parameters, typename and class are equivalent. §14.1.2:
There is no semantic difference
between class and typename in a
template-parameter.
typename however is possible in another context when using templates - to hint at the compiler that you are referring to a dependent type. §14.6.2:
A name used in a template declaration
or definition and that is dependent on
a template-parameter is assumed not to
name a type unless the applicable name
lookup finds a type name or the name
is qualified by the keyword typename.
Example:
typename some_template<T>::some_type
Without typename the compiler can't tell in general whether you are referring to a type or not.
While there is no technical difference, I have seen the two used to denote slightly different things.
For a template that should accept any type as T, including built-ins (such as an array )
template<typename T>
class Foo { ... }
For a template that will only work where T is a real class.
template<class T>
class Foo { ... }
But keep in mind that this is purely a style thing some people use. Not mandated by the standard or enforced by compilers
No difference
Template type parameter Container is itself a template with two type parameters.
There is no difference between using <typename T> OR <class T>; i.e. it is a convention used by C++ programmers. I myself prefer <typename T> as it more clearly describes its use; i.e. defining a template with a specific type.
Note: There is one exception where you do have to use class (and not typename) when declaring a template template parameter:
template <template <typename> class T> class C { }; // valid!
template <template <typename> typename T> class C { }; // invalid!
In most cases, you will not be defining a nested template definition, so either definition will work -- just be consistent in your use.
This piece of snippet is from c++ primer book. Although I am sure this is wrong.
Each type parameter must be preceded by the keyword class or typename:
// error: must precede U with either typename or class
template <typename T, U> T calc(const T&, const U&);
These keywords have the same meaning and can be used interchangeably inside a template parameter list. A template parameter list can use both keywords:
// ok: no distinction between typename and class in a template parameter list
template <typename T, class U> calc (const T&, const U&);
It may seem more intuitive to use the keyword typename rather than class to designate a template type parameter. After all, we can use built-in (nonclass) types as a template type argument. Moreover, typename more clearly indicates that the name that follows is a type name. However, typename was added to C++ after templates were already in widespread use; some programmers continue to use class exclusively