Can alias templates (14.5.7) be explicitly specialised (14.7.3)?
My standard-fu fails me, and I can't find a compiler to test on.
The text "when a template-id refers to the specialization of an alias template" implies yes, but then the example appears to refer to something else, implying no.
NB. I'm working from n3242, one behind the FDIS, in which the title of this section is "Aliase templates". Lol.
What the Standard means by "specialization" is the transformation of a generic template to a more specialized entity. For example, instantiating a non-member class template yields a class that's not a template anymore. The term "specialization" is two fold, and can refer to a generated specialization (which is a specialization that was instantiated, possibly from a partial specialization) and to an explicit specialization (which is what you referred to).
Alias templates aren't instantiated and there aren't specializations of them. There is nothing they could instantiate to. Instead, whenever their name is followed by a template argument list, the type denoted is the type you get by replacing the name and argument list by the alias'ed type, replacing all template parameter references with the arguments given in the argument list. That is, rather than the specialization of it being an alias, the alias template itself serves as an alias, without the need to instantiate anything. This replacement is done very early. Consider:
template<typename T> using ref = T&;
template<typename T> void f(ref<T> x) { x = 10; }
int main() { int a; f(a); return a; /* 10 */ }
The replacement is done at the time ref<T> is named (such a names are used to refer to class or function template specializations; hence the spec describes such names to "refer to the specialization of an alias template"). That is, the parameter of f has type T&, and thus, T can be deduced. This property is preventing explicit or partial specializations of alias templates. Because in order to pick the correct specialization of ref, it needs to know T. But to know it, it needs to compare ref<T> against the argument type to deduce T. It's summarized in the paper N1406, "Proposed addition to C++: Typedef Templates", section 2.2
2.2 The Main Choice: Specialization vs. Everything Else
After discussion on the reflectors and in the Evolution WG, it turns out that we have to choose between two mutually exclusive models:
A typedef template is not itself an alias; only the (possibly-specialized) instantiations of the typedef template are aliases. This choice allows us to have specialization of typedef templates.
A typedef template is itself an alias; it cannot be specialized. This choice would allow:
deduction on typedef template function parameters (see 2.4)
a declaration expressed using typedef templates be the same as the declaration without
typedef templates (see 2.5)
typedef templates to match template template parameters (see 2.6)
It should be noted that the quoted paper, which favors option 1, did not make it into C++0x.
EDIT: Because you desperately want to have a spec quote saying so explicitly. 14.5p3 is one that does
Because an alias-declaration cannot declare a template-id, it is not possible to partially or explicitly specialize an alias template.
Bjarne says:
Specialization works (you can alias a set of specializations but you cannot specialize an alias)
And, whilst not an explicit rule, "alias templates" are missing from the following list at 14.7.3/1:
An explicit specialization of any of the following:
function template
class template
member function of a class template
static data member of a class template
member class of a class template
member class template of a class or class template
member function template of a class or class template
can be declared[...]
I think that this is the best guarantee you'll get.
If you need pointwise mapping from something to types, this works(in gcc 4.8.3):
// int to type mapper
template<int BITS>
struct BitsToTypesMap
{
typedef void TYPE; // default
};
// pointwise mapping
template<>
struct BitsToTypesMap<32>{ typedef int TYPE; };
template<>
struct BitsToTypesMap<8>{ typedef char TYPE; };
template<>
struct BitsToTypesMap<16>{ typedef short TYPE; };
// cute wrapping
template<int BITS> using MyScalarType = typename BitsToTypesMap<BITS>::TYPE;
// TEST
template<int BITS>
MyScalarType<BITS>
Add ( MyScalarType<BITS> x, MyScalarType<BITS> y )
{
return x+y;
}
int
test()
{
MyScalarType<32> i=Add<32>(1,2);
MyScalarType<8 > b=Add<8 >(1,2);
MyScalarType<16> s=Add<16>(1,2);
return i+b+s;
}
I am not sure if I understand the question, but in any case I tried to simulate specialization of alias template.
I assume that the idea is to restrict the alias template to certain (pattern matched type); something that we used to do with this sort of code:
template<class Vector> struct old_style;
template<class T> struct old_style<std::vector<T> >{
typedef typename std::vector<T>::value_type type;
};
(this is just an example, there are other way to extract the value_type of a generic std::vector).
Now to the aliases:
template<class Vector> using new_style = typename Vector::value_type;
It does the same work, but this does not replace old_stype<...>::type, since it is not as restrictive. The first try to have a perfect alias replacement is this hypothetical code:
//template<class Vector> using new_style2; // error already here
//template<class T> using new_style2<std::vector<T> > = typename Vector::value_type;
Unfortunately it doesn't compile (in theory because of nominal reasons stated in other answers and in the standard, in practice I guess there is no fundamental reason for this to be a limitation). Fortunately one can fallback to the old fashioned struct::type way of doing it an only use the new alias template feature to forward the work,
template<class Vector> struct new_style2_aux;
template<class T> struct new_style2_aux<std::vector<T> >{
typedef typename std::vector<T>::value_type type;
};
template<class Vector> using new_style2 = typename new_style2_aux<Vector>::type;
One can make it automatic with a define
#define SPECIALIZED_ALIAS_TEMPLATE(NamE, Pattern_arG, PatterN_expR, DefinitioN) \
template<class> struct NamE ## _aux; \
template<Pattern_arG> struct NamE ## _aux<PatterN_expR>{ \
typedef DefinitioN type; \
}; \
template<class NamE ## _dummy> using NamE = typename NamE ## _aux< NamE ## _dummy >::type;
Which can be used as:
SPECIALIZED_ALIAS_TEMPLATE(new_style3, class T, std::vector<T>, typename std::vector<T>::value_type);
If one needs an arbitrary number of specializations (or non local in the code), one has to use a more complicated define in two parts, one for declaring and one for specializing (as it should be):
#define DECLARE_ALIAS_TEMPLATE(NamE)\
template<class> struct NamE ## _aux;\
template<class NamE ## _dummy> using NamE = typename NamE ## _aux< NamE ## _dummy >::type;
#define SPECIALIZE_ALIAS_TEMPLATE(NamE, Pattern_arG, PatterN_expR, DefinitioN)\
template<Pattern_arG> struct NamE ## _aux<PatterN_expR>{ \
typedef DefinitioN type; \
};
Used as follows:
DECLARE_ALIAS_TEMPLATE(new_style4);
SPECIALIZE_ALIAS_TEMPLATE(new_style4, class T, std::vector<T>, typename std::vector<T>::value_type);
SPECIALIZE_ALIAS_TEMPLATE(new_style4, class T, std::set<T>, typename std::set<T>::value_type);
All the code above can be copied and pasted to test:
#include<vector>
#include<map>
// ... paste code above //
int main(){
old_style<std::vector<double> >::type a; // is a double
// old_style<std::set<double> >::type a; // error (should work only for std::vector)
new_style2<std::vector<double> > b; // is double
// new_style2<std::set<double> > c; // error (should work only for std::vector)
new_style3<std::vector<double> > d; // is double
// new_style3<std::set<double> > d; // error (should work only for std::vector)
new_style4<std::vector<double> > e; // is double
new_style4<std::set<double> > f; // is double, this is another specialization
return 0;
}
Sorry if this is not what you are looking for. I believe it can be used with variadic templates, and with extra template arguments (in the specialization) but didn't test it.
Improvements are very welcomed.
Related
The short version (Read if you have no patience like me):
What does setting a typename template parameter to a default of 0 do in C++?
My enable if struct:
/**
* #brief Can be used to enable a template definition using a boolean value
*/
template<lfBool Condition>
struct lfEnableIf
{ };
template<>
struct lfEnableIf<true>
{
typedef lfInt Type;
};
My boolen constant struct:
template<lfBool Val>
struct lfBoolConstant
{
static const lfBool Value = Val;
};
typedef lfBoolConstant<true> lfTrueType;
typedef lfBoolConstant<false> lfFalseType;
My type trait struct (just one of the specializations):
template <typename NumT> struct lfIsArithmetic : lfFalseType{};
template <> struct lfIsArithmetic<lfChar> : lfTrueType{};
And finally my usage of it all:
template<typename T, typename lfEnableIf<lfIsArithmetic<T>::Value>::Type = 0>
struct Test
{
static void print()
{
std::cout << "OK!" << std::endl;
}
};
int main()
{
Test<lfFloat>::print();
Test<lfBool>::print();
return 0;
}
Sorry for the poor for formatting I am writing this on my cell phone.
The long version (Please read if you have the patience so you understand why there is not much code):
So, I am on vacation and don't have access to my workstation or laptop so I thought I would try out AIDE, which if you are unaware is an IDE for android that can compile C++. At home I am designing a game engine that includes Boost and I figured I would try to create something similar to the enable_if structures that are in the Boost.Core library. I got it mostly working but it would not compile unless I set the enable if structure in the template I was enabling to default to 0! This is what you do with the Boost enable_if and disable_if templates. So what does setting a typename template parameter to a default of 0 do in C++?
Thanks!
This line
template<typename T, typename lfEnableIf<lfIsArithmetic<T>::Value>::Type = 0>
declares a named template type parameter T and a nameless template value parameter of type lfEnableIf<lfIsArithmetic<T>::Value>::Type, i.e. the second parameter declarations is basically a more convoluted version of simple
template <int N = 0> struct S {};
The type lfEnableIf<lfIsArithmetic<T>::Value>::Type resolves into type lfInt when the enabling condition is met, meaning that the whole thing in such cases is equivalent to
template<typename T, lfInt = 0>
However, since type of that second template parameter is a nested type of a dependent template lfEnableIf, you are required to use the keyword typename to tell the compiler that member Type actually refers to a type and not to something else (i.e. to disambiguate the situation).
Again, the second parameter of the template is nameless, but you can give it a name, if you wish. It won't change anything
template<typename T, typename lfEnableIf<lfIsArithmetic<T>::Value>::Type V = 0>
In the above example I called it V. The name of that parameter is not used anywhere in the template, which is why there's no real need to specify it explicitly. It is a dummy parameter, which is also the reason it has a dummy default value (you can replace 0 with 42 - it won't change anything either).
In this case keyword typename creates a misleading similarity between the two parameter declarations of your template. In reality in these parameter declarations the keyword typename serves two very very very different unrelated purposes.
In the fist template parameter declaration - typename T - it declares T as a template type parameter. In this role keyword typename can be replaced with keyword class
template <class T, ...
In the second declaration - typename lfEnableIf<lfIsArithmetic<T>::Value>::Type = 0 - it serves a secondary purpose - it just tells the compiler that lfEnableIf<lfIsArithmetic<T>::Value>::Type is a type and thus turns the whole thing into a value parameter declaration. In this role keyword typename cannot be replaced with keyword class.
I was wondering if it's possible to write a template function that can take any other arbitrary template as a parameter and properly match the template name (i.e. not just the resulting class). What I know to work is this:
template<template<typename ...> class TemplateT, typename... TemplateP>
void f(const TemplateT<TemplateP...>& param);
Which will match for instance for f(std::vector<int>()) or f(std::list<int>()) but will not work for f(std::array<int, 3>()), as the second parameter is a size_t and no type.
Now I guess one could do something crazy like:
template<template<typename ...> class TemplateT, size... Sizes, typename... TemplateP>
void f(const TemplateT<Sizes..., TemplateP...>& param);
Hoping that the compiler would properly derive either the TemplateP ellipsis or the Sizes ellipsis to be empty. But not only is it ugly, it also will still just work for templates that take either types or size_t parameters. It still won't match arbitrary templates for instance with bool parameters.
Same goes for an approach with overloading:
template<template<typename ...> class TemplateT, typename... TemplateP>
void f(const TemplateT<TemplateP...>& param);
template<template<typename ...> class TemplateT, size... Sizes>
void f(const TemplateT<Sizes...>& param);
Furthermore, such approach wont' work if we would like to mix size_t and typenames. So what would be required to match anything would be something like this, where there are no constraints at all to what is allowed in the ellipsis:
template<template<...> class TemplateT, ... Anything>
void f(const TemplateT<Anything...>& param);
That syntax doesn't work but maybe there's other syntax to define something like this?
This is mainly me wondering what is possible in the language, thought there might actually be a use for it, if you have different templates where the first parameter is always fixed and you would like to change it based on the return type and keep everything else. Something like this:
template<
template<typename ValueT, ...> class TemplateT,
... Anything,
typename ValueT,
typename ResultT = decltype(some_operation_on_value_t(std::declval<ValueT>())>
TemplateT<ResultT, Anything...> f(const TemplateT<ValueT, Anything...>& in);
So, any way to make this work in a completely generic way using pattern matching?
This is not purely a thought experiment, as the use case for this where I was stuck was to create pure functional primitives that operate on containers and will implicitly construct immutable result containers. If the result container has a different data type we need to know the type the container operates on, so the only requirement on any container would be that the first parameter of the template needs to be the input type so it can be replaced with a different output type in the result, but the code should be oblivious to any template argument coming after that and should not care whether it's a type or a value.
Your interesting construct has two levels with variadic templates.
An outer variadic template parameter list TemplateP & Sizes for a function template
An inner parameter pack as the template parameters of your template template parameter TemplateT, a class template
First, let's look at the inner TemplateT class: why can the ellipsis operator not not match something like TemplateT< int, 2 >? Well, the standard defines variadic templates in §14.5.3 as
template<class ... Types> struct Tuple { };
template<T ...Values> struct Tuple2 { };
where the template argument pack in the first case may only match types and in the second version only values of type T. In particular,
Tuple < 0 > error; // error, 0 is not a type!
Tuple < T, 0 > error2; // T is a type, but zero is not!
Tuple2< T > error3; // error, T is not a value
Tuple2< T, 0 > error4; // error, T is not a value
are all malformed. Furthermore, it is not possible to fall back to something like
template<class ... Types, size_t ...Sizes> struct Tuple { };
because the standard states in §14.1.11:
If a template-parameter of a primary class template or alias template is a template parameter pack, it
shall be the last template-parameter. A template parameter pack of a function template shall not be followed
by another template parameter unless that template parameter can be deduced from the parameter-type-list
of the function template or has a default argument (14.8.2).
In other words, for class templates only one variadic parameter pack may appear in the definition. Therefore the above (double)-variadic class definition is malformed. Because the inner class always needs such a combination, it is impossible to write something as general as you conceived.
What can be rescued? For the outer function template, some shards can be put together, but you won't like it. As long as the second parameter pack can be deduced from the first, two parameter packs may appear (in a function template). Therefore, a function such as
template < typename... Args, size_t... N > void g(const std::array< Args, N > &...arr);
g(std::array< double, 3 >(), std::array< int, 5>());
is allowed, because the integer values can be deduced. Of course, this would have to be specialized for every container type and is far from what you had imagined.
You must have a metafunction that rebinds the type of container.
Because you cannot just replace first template parameter:
vector<int, allocator<int> > input;
vector<double, allocator<int> > just_replaced;
vector<double, allocator<double> > properly_rebound;
So, just write such a metafunction for known set of containers.
template<class Container, class NewValue> class rebinder;
// example for vectors with standard allocator
template<class V, class T> class rebinder< std::vector<V>, T > {
public:
typedef std::vector<T> type;
};
// example for lists with arbitrary allocator
template<class V, class A, class T> class rebinder< std::list<V,A>, T > {
typedef typename A::template rebind<T>::other AT; // rebind the allocator
public:
typedef std::list<T,AT> type; // rebind the list
};
// example for arrays
template<class V, size_t N> class rebinder< std::array<V,N>, T > {
public:
typedef std::array<T,N> type;
};
Rules of rebinding may vary for different containers.
Also you might require a metafunction that extracts value type from arbitrary container, not only std-conformant (typedef *unspecified* value_type)
template<class Container> class get_value_type {
public:
typedef typename Container::value_type type; // common implementation
};
template<class X> class get_value_type< YourTrickyContainer<X> > {
......
public:
typedef YZ type;
};
It would be awesome if we had such thing, as it would allow us to write a is_same_template trait in a breeze.
Until then, we specialize all the way.
I have learned that data structures can be created using templates in the following way:
template<typename T>
struct X {
T weight;
int age;
};
The functions can also use templates in the following way:
template <class T>
T func_name(int age, T human) {
something_here;
}
One of the difference s is that in the first case we use typename while in the second case we use class.
I found code that contains the following:
template<typename S, typename T>
bool is_null(const row<T>& r)
So, what I cannot understand is why we use typename (and not class) in combination with functions. Shouldn't we use class?
In this context, there is no technical difference between the keyword typename and the keyword class. It's just a matter of style. The meaning of your first two code examples would not change one bit if they started with template<class T> struct X and template <typename T> T func_name(int age, T human). (I tend to use class when I mean to imply the template parameter should be a class, and not something like int.)
When template was first introduced, it ONLY allowed the existing keyword class as an indicator "this is a template argument". Since this becomes rather daft when the template argument isn't actually a class (a function pointer, integer type, or some other "not a class" type), the typename was introduced to make it more clear that template<typename T> struct something { T x; }; allows something<int> a; as well as something<name_of_class> a;.
For all intents and purposes, class and typename in the case of template parameters is interchangeable, and it's just a matter of style which you choose to do [most people probably prefer if you stick to one, not mixing the two - or, perhaps use class when the type HAS TO be a class, and typename when it can be "any" type].
In the context of template parameter definitions the keywords typename and class are synonymous.
Just about everyone has a convention they tend to stick with. I personally prefer to always use class here and reserve the typename keyword for its other use.
The other use for typename is to disambiguate a dependent type in a template definition or declaration.
Here is an example from wikipedia:
template <typename T>
void foo(const T& t)
{
// declares a pointer to an object of type T::bar
T::bar * p;
}
struct StructWithBarAsType {
typedef int bar;
};
int main() {
StructWithBarAsType x;
foo(x);
}
If you look closely you will notice in the line T::bar * p;, bar is dependent on a template parameter T which is ambiguous to the compiler as bar can be either a type or a value depending on the context of the type T used for instantiating the template. The default is to treat bar as a value so the meaning would be to multiply T::bar by p which is not what we want.
The solution is to qualify the dependent type with the typename keyword.
typename T::bar * p;
This alerts the compiler to the fact that we intend to treat bar as a type.
There's only one spot where they differ (when declaring template parameters), and that is when using template-templates.
The following is well-defined C++
template <template <typename> class TT> struct example_one {};
while this is not:
template <template <typename> typename TT> struct example_two {};
Since it seems like you're just starting out with C++/templates, this corner case won't concern you for a while :-) Aside from the above, class template, function template, it doesn't matter: typename and class are synonymous.
I currently have a class template that takes a series of types. Each type may need to be instantiated with the class, itself. What I currently have is something like this:
template <typename... Types>
struct TypeList; // Not defined
struct Placeholder; // Not defined
template <typename Types, typename AnotherType = Default>
class MyClass
{
// ...
};
You can then use it like this:
typedef MyClass<TypeList<Container1<Placeholder>, Container2<std::string,
Placeholder>, OtherType>, OptionalType> MyTypedef;
MyTypedef my_object;
MyClass will replace appearances of Placeholder with itself, use the resulting types, and all is well.
The problem occurs when I try to do something like either of these:
MyTypedef *my_ptr = &my_object;
my_free_function(my_object);
Both of these cause a compiler error, because the compiler tries to instantiate Container1<Placeholder> and Container2<std::string, Placeholder> to do argument dependent lookup (ADL), and this instantiation with Placeholder, itself, fails.
I know it is possible to avoid ADL by doing, e.g.,
MyTypedef *my_ptr = std::addressof(my_object);
(my_free_function)(my_object);
However, I don't want to burden the user of MyClass with having to constantly suppress ADL. Is there another, straightforward way to have the user provide a list of types without those types being used for ADL?
Okay, I got everything working. The trick was to use a dependent type instead of using a template, directly. My final solution was to define TypeList as follows:
template <typename... Types>
struct TypeList
{
private:
struct Holder
{
private:
typedef TypeList<Types...> InnerTypeList;
template <typename Types, typename AnotherType>
friend class MyClass;
};
public:
typedef Holder type;
};
Then, the users of MyClass can do
typedef MyClass<TypeList<Container1<Placeholder>, Container2<std::string,
Placeholder>::type, OtherType>, OptionalType> MyTypedef;
MyTypedef my_object;
Note the addition of '::type'
Finally, in MyClass, I replaced
typedef typename SubstituteType<Types, Placeholder, MyClass>::type InternalTypeList;
with
typedef typename SubstituteType<Types::InnerTypeList, Placeholder, MyClass>::type
InternalTypeList;
giving me the same type for InternalTypeList as before.
Because the dependent type Holder has no template parameters of it's own, the compiler doesn't have to instantiate the Placeholder types for ADL purposes, and everything works properly.
On occasion I've seen some really indecipherable error messages spit out by gcc when using templates... Specifically, I've had problems where seemingly correct declarations were causing very strange compile errors that magically went away by prefixing the typename keyword to the beginning of the declaration... (For example, just last week, I was declaring two iterators as members of another templated class and I had to do this)...
What's the story on typename?
Following is the quote from Josuttis book:
The keyword typename was introduced to
specify that the identifier that
follows is a type. Consider the
following example:
template <class T>
Class MyClass
{
typename T::SubType * ptr;
...
};
Here, typename is used to clarify that
SubType is a type of class T. Thus,
ptr is a pointer to the type
T::SubType. Without typename, SubType
would be considered a static member.
Thus
T::SubType * ptr
would be a multiplication of value
SubType of type T with ptr.
Stan Lippman's BLog post suggests :-
Stroustrup reused the existing class
keyword to specify a type parameter
rather than introduce a new keyword
that might of course break existing
programs. It wasn't that a new keyword
wasn't considered -- just that it
wasn't considered necessary given its
potential disruption. And up until the
ISO-C++ standard, this was the only
way to declare a type parameter.
So basically Stroustrup reused class keyword without introducing a new keyword which is changed afterwards in the standard for the following reasons
As the example given
template <class T>
class Demonstration {
public:
void method() {
T::A *aObj; // oops …
// …
};
language grammar misinterprets T::A *aObj; as an arithmetic expression so a new keyword is introduced called typename
typename T::A* a6;
it instructs the compiler to treat the subsequent statement as a declaration.
Since the keyword was on the payroll,
heck, why not fix the confusion caused
by the original decision to reuse the
class keyword.
Thats why we have both
You can have a look at this post, it will definitely help you, I just extracted from it as much as I could
Consider the code
template<class T> somefunction( T * arg )
{
T::sometype x; // broken
.
.
Unfortunately, the compiler is not required to be psychic, and doesn't know whether T::sometype will end up referring to a type name or a static member of T. So, one uses typename to tell it:
template<class T> somefunction( T * arg )
{
typename T::sometype x; // works!
.
.
In some situations where you refer to a member of so called dependent type (meaning "dependent on template parameter"), the compiler cannot always unambiguously deduce the semantic meaning of the resultant construct, because it doesn't know what kind of name that is (i.e. whether it is a name of a type, a name of a data member or name of something else). In cases like that you have to disambiguate the situation by explicitly telling the compiler that the name belongs to a typename defined as a member of that dependent type.
For example
template <class T> struct S {
typename T::type i;
};
In this example the keyword typename in necessary for the code to compile.
The same thing happens when you want to refer to a template member of dependent type, i.e. to a name that designates a template. You also have to help the compiler by using the keyword template, although it is placed differently
template <class T> struct S {
T::template ptr<int> p;
};
In some cases it might be necessary to use both
template <class T> struct S {
typename T::template ptr<int>::type i;
};
(if I got the syntax correctly).
Of course, another role of the keyword typename is to be used in template parameter declarations.
The secret lies in the fact that a template can be specialized for some types. This means it also can define the interface completely different for several types. For example you can write:
template<typename T>
struct test {
typedef T* ptr;
};
template<> // complete specialization
struct test<int> { // for the case T is int
T* ptr;
};
One might ask why is this useful and indeed: That really looks useless. But take in mind that for example std::vector<bool> the reference type looks completely different than for other Ts. Admittedly it doesn't change the kind of reference from a type to something different but nevertheless it could happen.
Now what happens if you write your own templates using this test template. Something like this
template<typename T>
void print(T& x) {
test<T>::ptr p = &x;
std::cout << *p << std::endl;
}
it seems to be ok for you because you expect that test<T>::ptr is a type. But the compiler doesn't know and in deed he is even advised by the standard to expect the opposite, test<T>::ptr isn't a type. To tell the compiler what you expect you have to add a typename before. The correct template looks like this
template<typename T>
void print(T& x) {
typename test<T>::ptr p = &x;
std::cout << *p << std::endl;
}
Bottom line: You have to add typename before whenever you use a nested type of a template in your templates. (Of course only if a template parameter of your template is used for that inner template.)
Two uses:
As a template argument keyword (instead of class)
A typename keyword tells the compiler that an identifier is a type (rather than a static member variable)
template <typename T> class X // [1]
{
typename T::Y _member; // [2]
}
I think all of the answers have mentioned that the typename keyword, is used in two different cases:
a) When declaring a template type parameter. e.g.
template<class T> class MyClass{}; // these two cases are
template<typename T> class MyNewClass{}; // exactly the same.
Which there is no difference between them and they are EXACTLY the same.
b) Before using a nested dependent type name for a template.
template<class T>
void foo(const T & param)
{
typename T::NestedType * value; // we should use typename here
}
Which not using typename leads to parsing/compilation errors.
What I want to add to the second case, as mentioned in Scot Meyers book Effective C++, is that there is an exception of using typename before a nested dependant type name. The exception is that if you use the nested dependant type name either as a base class or in a member initialization list, you should not use typename there:
template<class T>
class D : public B<T>::NestedType // No need for typename here
{
public:
D(std::string str) : B<T>::NestedType(str) // No need for typename here
{
typename B<T>::AnotherNestedType * x; // typename is needed here
}
}
Note: Using typename for the second case (i.e. before nested dependent type name) is not needed since C++20.
#include <iostream>
class A {
public:
typedef int my_t;
};
template <class T>
class B {
public:
// T::my_t *ptr; // It will produce compilation error
typename T::my_t *ptr; // It will output 5
};
int main() {
B<A> b;
int my_int = 5;
b.ptr = &my_int;
std::cout << *b.ptr;
std::cin.ignore();
return 0;
}