Officially, What Is Typename For

Officially, what is typename for?

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.

When is the typename keyword necessary?

Short answer: Whenever referring to a nested name that is a dependent name, i.e. nested inside a template instance with unknown parameter.

Long answer: There are three tiers of entities in C++: values, types, and templates. All of those can have names, and the name alone doesn't tell you which tier of entity it is. Rather, the information about the nature of a name's entity must be inferred from the context.

Whenever this inference is impossible, you have to specify it:

template <typename> struct Magic; // defined somewhere else

template <typename T> struct A
{
static const int value = Magic<T>::gnarl; // assumed "value"

typedef typename Magic<T>::brugh my_type; // decreed "type"
// ^^^^^^^^

void foo() {
Magic<T>::template kwpq<T>(1, 'a', .5); // decreed "template"
// ^^^^^^^^
}
};

Here the names Magic<T>::gnarl, Magic<T>::brugh and Magic<T>::kwpq had to be expliciated, because it is impossible to tell: Since Magic is a template, the very nature of the type Magic<T> depends on T -- there may be specializations which are entirely different from the primary template, for example.

What makes Magic<T>::gnarl a dependent name is the fact that we're inside a template definition, where T is unknown. Had we used Magic<int>, this would be different, since the compiler knows (you promise!) the full definition of Magic<int>.

(If you want to test this yourself, here's a sample definition of Magic that you can use. Pardon the use of constexpr in the specializaation for brevity; if you have an old compiler, feel free to change the static member constant declaration to the old-style pre-C++11 form.)

template <typename T> struct Magic
{
static const T gnarl;
typedef T & brugh;
template <typename S> static void kwpq(int, char, double) { T x; }
};
template <> struct Magic<signed char>
{
// note that `gnarl` is absent
static constexpr long double brugh = 0.25; // `brugh` is now a value
template <typename S> static int kwpq(int a, int b) { return a + b; }
};

Usage:

int main()
{
A<int> a;
a.foo();

return Magic<signed char>::kwpq<float>(2, 3); // no disambiguation here!
}

What is the purpose of typename in C++

The typename keyword just tells the compiler that whatever identifier follows is a valid type. This is important in templates because the compiler may not yet have the definitions of the types used in the templates, but you still want to be able to use part of that type's definition (e.g., like key_type above). If you didn't use the typename keyword, the compiler would error out on that symbol because it doesn't know what it is. This comes in to play often when you use template instances as template parameters.

Clear as mud?

Typename Keyword for SFINAE

The keyword typename is used here because you are accessing a type member of a template type argument.

It is completely unrelated except for the fact that if T is Bar then it should expose a it type member to gain access to the overload.

Substitution Failure Is Not An Error is a template meta programming pattern that relies on "removing" overloads that could not compile

The 'typename' word in C++

In simple words, "dependent name" in a template code is some type which is constructed within the definition of the template.

In your example, the types CVertex, CEdge, CFace, CHalfEdge are template parameters. All other names which are declared with usage of the parameters are dependent.

They can be type names but can be something else, e.g. name of the functions or variables. Compiler has to understand, whether a given dependent name is a type or a variable. It is actually compiler-dependent. To help the compiler, you add "typename" to indicate that this identifier is a type.

Imagine, that your code does not have #include <vector> but instead uses forward declaration:
namespace std { template<class T, class Alloc=allocator<T> > class vector; }

Then compiler has no idea which names within class vector are types and which are member names. It only knows that vector is a type.

For example, in the code typename std::vector<TLoop*> m_loops; most likely the word typename can be omitted for most compilers because they know that vector is a type.

However, the code std::vector<TLoop*>::const_iterator will sure require typename: for (typename std::vector<TLoop*>::const_iterator it = loops().begin(); ...

Hope it helps.

How to use typename in c++?

You can read typedef typename std::vector::size_type size_type like this:

typedef typename std::vector::size_type size_type, just like typedef __int64 INT64.

Why we need typename beforce std::vector::size_type? It just tells the compiler that std::vector::size_type is a type not a normal class member. It's used for disambiguation.

But I think maybe some compiler can auto detect std::vector::size_type is a type.

So, typedef just creates an alias for an existing type, and typename tells the compile that std::vector::size_type is a type not a normal class member.

Reason for requiring typename in a template definition

While you've links to a thorough answer, it's a lot to wade through. So - put as simply as I can - the point is that the compiler does indeed know that T is a type as you say, but using that information and even having seen the included source code for std::set, it can't be sure whether the iterator identifier inside the set<T> will name a type, a function, or a variable. This might seem surprising as if you look at the set<> template you can work it out, but remember that somewhere between the compiler parsing your f<>() template and before it's instantiated, a specialisation for set<T> may be specified that uses identifier for a non-type, or simply lacks it altogether.

So, the typename keyword just tells the compiler, hey - whatever happens you can expect iterator to name a type, and perform some validatition of the f<>() template code on that basis without waiting to see an instantiation.

what is difference of two kinds of template examples?

These two lines of code operate in a slightly different way:

template <typename N, typename = std::enable_if_t<std::is_arithmetic<N>::value
// or with name
template <typename N, typename second = std::enable_if_t<std::is_arithmetic<N>::value

define a type as template (which is unnamed in the 1st case) and provides a default value (std::enable_if...). This boils down to <N=int, second=int> in your case.
This post is helpful for understanding where to use template / typename. Whereas

2. template <typename N, std::enable_if_t<std::is_arithmetic<N>::value >>

has a non-type template argument. This boils down to <N=int, enable_if<...>::type second=?> The major difference between the two versions and the reason for one version 'working' out of the box is, that this time, the value that this non-type template assumes, is not specified by default. You would need to specify it or write sth like

3. template <typename N, std::enable_if_t<std::is_arithmetic<N>::value >* = nullptr>

The following version is equivalent, but provides a name:

4. template <typename N, std::enable_if_t<std::is_arithmetic<N>::value >* second = nullptr>

TLDR

You have to also specify the default value for the enable-if guard in the second case, which the compiler cannot deduce (or specify both template arguments when calling, which is not desired). The compiler error hints at that if the line (not working) is not exchanged with line (3) above:

/home/juli/te.cc:37:5: note: candidate: ‘template<class N, typename std::enable_if<std::is_arithmetic<_Tp>::value, void>::type <anonymous> > MyVector::MyVector(const N&)’
37 | MyVector(const N& x)
| ^~~~~~~~
/home/juli/te.cc:37:5: note: template argument deduction/substitution failed:
/home/juli/te.cc:63:30: note: couldn’t deduce template parameter ‘<anonymous>’
63 | MyVector mv3 = MyVector(x);

Depending on what standard you are using, looking into the newly introduced concepts feature of c++2a might be interesting.

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.



Related Topics



Leave a reply



Submit