Why Do I Need to Use Typedef Typename in G++ But Not VS

Why do I need to use typedef typename in g++ but not VS?

The typename is required by the standard. Template compilation requires a two step verification. During the first pass the compiler must verify the template syntax without actually supplying the type substitutions. In this step, std::map::iterator is assumed to be a value. If it does denote a type, the typename keyword is required.

Why is this necessary? Before substituing the actual KEY and VALUE types, the compiler cannot guarantee that the template is not specialized and that the specialization is not redefining the iterator keyword as something else.

You can check it with this code:

class X {};
template <typename T>
struct Test
{
typedef T value;
};
template <>
struct Test<X>
{
static int value;
};
int Test<X>::value = 0;
template <typename T>
void f( T const & )
{
Test<T>::value; // during first pass, Test<T>::value is interpreted as a value
}
int main()
{
f( 5 ); // compilation error
X x; f( x ); // compiles fine f: Test<T>::value is an integer
}

The last call fails with an error indicating that during the first template compilation step of f() Test::value was interpreted as a value but instantiation of the Test<> template with the type X yields a type.

Why are class-level typedefs not inherited from tempates?

They are actually "inherited" (by which I mean they are accessible as members of c2<t>). However, all members (not just types) inherited from a dependent base class (a base class which depends on template parameters) are only looked up inside the class template when the compiler has reason to believe they're dependent.

In other words, when parsing the definition of the template c2, the compiler doesn't know what t will be when instantiating, and so it has no means of guessing what the definition of c1<t> will be (remember that it could be specialised later). So it does not look into c1 at all when looking up a name found in c2. So type_name is not found.

However, if you make the name lookup explicitly depend on template parameters somehow, the compiler will realise it has to postpone the lookup until instantiation. This would happen in these cases:

// Case 1
template<typename t> class c2 : public c1<t>
{
public:
void fn2(typename c1<t>::type_name x) {}
};

// Case 2
template<typename t> class c2 : public c1<t>
{
public:
void fn2(typename c2::type_name x) {}
};

In both cases, the thing to the left of :: depends on template parameters, so the compiler will know to postpone lookup until instantiation.

Also note that you need to add the typename keyword; without it, the compiler would have no idea whether the thing to the right of :: is a type or a non-type member. The language standard dictates to treat it as a non-type member in such case, which leads to a syntax error.

However, when c2 is not a template, the definition of all its base classes is fully known when it's parsed, so there is no problem in looking up the name.

You can learn more details about this two-phase lookup in this somewhat related SO question.

Template's member typedef use in parameter undeclared identifier in VS but not GCC

I think this can be caused by a few circumstances

  • unbounded_int_type is a non-dependent type (defined at 14.6.2.1)
  • Its declaration appears in the class template. Because it's non-dependent, its name has to be resolved to a declaration at the time the member function is defined.

I suspect that Visual C++ is not able to do this lookup, and errors out instead. As someone else mentions, you can explicitly qualify the type-names in the member function definition. The types are then dependent, and this will trigger the compiler's mechanism to delay name lookup until instantiation.

template<class UInt>
void uii_ops_impl<
UInt, typename make_signed<typename UInt::digit_type>::type,
true >::add(typename
/* repeat-that-beast uii_ops...true> here */
::unbounded_int_type& lhs,
typename /* and here too */::integral_type rhs)
{
// ....
}

typedef typename and Dependent scope

Your Ideone sample fixed:

#include <iostream>

#include <vector>
#include <iterator>


template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
class PtrVector
{
private:
typedef std::vector<_Tp, _Alloc> VectrorT;
typedef typename std::vector<_Tp, _Alloc>::const_iterator VTConstIter;
// ^^^^^^^^ ^^^^^^^^^^^^^^^^

public:

typename std::vector<_Tp, _Alloc>::const_iterator test(){}
// ^^^^^^^^ ^^^^^^^^^^^^^^^^
VTConstIter test2(){}

};


int main() {
return 0;
}

As for your comments, see these variants also:

// ...
typedef typename VectrorT::const_iterator VTConstIter; // also works
// ...
typename VectrorT::const_iterator test(){} // also works
// ...

I hope that clarifies abit further what's going on in the compilers guts.

Why is the use of typedef in this template necessary?

This compiles as well and reveals the source of VC++ confusion -- allocator type. Apparently outside of the class VS selects different default. Or maybe it can't recognize them to be the same.

Compiles on VS2008 (as is) and VS2003 (with space between >>)

template <class T>
class CFoo
{
public:
T m_t;
};

template <class T>
class CFooVector : public std::vector<CFoo<T>>
{
public:
void SetToFirst(typename std::vector<CFoo<T>, typename CFooVector::_Alloc>::iterator & iter);

};

template <class T>
void CFooVector<T>::SetToFirst( typename std::vector<CFoo<T>, typename CFooVector::_Alloc>::iterator & iter )
{
iter = begin();
}

GCC 3.4 wanted this->begin() and space, but otherwise it can compile the code without explicit allocator type... Definitely looks like MS compiler not as smart as it should be...

typedef throwing error even with typename keyword

Thanks everyone who helped. The problem was indeed somewhere else. Let me explain:

In C#, we use generics (which are rough equivalents of C++ templates system) in class definition and can apply constraints on them:

class Node<T> where T:SomeClass { ... }

which allows us to instantiate objects of type T inside this class. Those objects will have all members of SomeClass automatically. You get nice intellisense as a bonus too. Great thing about this system is that the integrity of this class can be verified at compile time without us having to instantiate an object of type Node<T>.

[disclaimer: The following is my understanding. Correct me if I'm wrong.]

C++ doesn't work this way. C++ will allow you to access anything against the template parameter (in my case it was State::Move). The templated class on its own doesn't/can't ensure that the template parameter will actually have a member named Move. Only when you instantiate an object of templated class, such as Node<SomeType> x;, it actually ensures that SomeType must contain a member named Move and throws error if that's not the case.

In my problem, I was instantiating an object of Node and passing it an int as template parameter, which obviously doesn't have any member named Move, so it was complaining (unfortunately pointing to a very wrong place, but that's another story). Replacing it with the appropriate type fixed the error for me.

Hope this helps someone down the road.

typedef using template arguments not working with g++

Based on the gcc error message, the problem is you claim A<T>::B is a type but it isn't: it a class template. Both gcc and clang are happy with

typedef A<T>::B<T> Ttype;

i.e., remove the typename. In the given context it wouldn't be possible to specialize B to be something different than what it obviously is anyway.

The using-alias does just the same with a different syntax:

using Ttype = A<T>::B<T>;

The notation using an extra template keyword first states that B is actually a template and then, in combination with the typename that the instantiation B<T> is a type:

typedef typename A<T>::template B<T> Ttype;

or

using Ttype = typename A<T>::template B<T>;

Since the class template B is local anyway, the qualification isn't really needed in this context, i.e.

typedef B<T> Ttype;

and

using Ttype = B<T>;

do work as well.

Why when a template class inherits from another template class, typedefs need to be respecified and functions calls qualified?

The fundamental reason is that classes can be specialized:

template<class T>
struct A {};

template<class T>
struct B : A<T> {
typedef typename A<T>::referent target;
void niceName() {A<T>::uglyName();}
};

template<class T>
struct A<T*> {
typedef T referent;
void uglyName();
};

B<int*>::target i; // OK: int

Of course, the reverse case (where the primary template defines useful things, and we simply fear that a specialization might change or remove them) is more common, which makes the rule seem arbitrary.

Where and why do I have to put the template and typename keywords?

(See here also for my C++11 answer)

In order to parse a C++ program, the compiler needs to know whether certain names are types or not. The following example demonstrates that:

t * f;

How should this be parsed? For many languages a compiler doesn't need to know the meaning of a name in order to parse and basically know what action a line of code does. In C++, the above however can yield vastly different interpretations depending on what t means. If it's a type, then it will be a declaration of a pointer f. However if it's not a type, it will be a multiplication. So the C++ Standard says at paragraph (3/7):

Some names denote types or templates. In general, whenever a name is encountered it is necessary to determine whether that name denotes one of these entities before continuing to parse the program that contains it. The process that determines this is called name lookup.

How will the compiler find out what a name t::x refers to, if t refers to a template type parameter? x could be a static int data member that could be multiplied or could equally well be a nested class or typedef that could yield to a declaration. If a name has this property - that it can't be looked up until the actual template arguments are known - then it's called a dependent name (it "depends" on the template parameters).

You might recommend to just wait till the user instantiates the template:

Let's wait until the user instantiates the template, and then later find out the real meaning of t::x * f;.

This will work and actually is allowed by the Standard as a possible implementation approach. These compilers basically copy the template's text into an internal buffer, and only when an instantiation is needed, they parse the template and possibly detect errors in the definition. But instead of bothering the template's users (poor colleagues!) with errors made by a template's author, other implementations choose to check templates early on and give errors in the definition as soon as possible, before an instantiation even takes place.

So there has to be a way to tell the compiler that certain names are types and that certain names aren't.

The "typename" keyword

The answer is: We decide how the compiler should parse this. If t::x is a dependent name, then we need to prefix it by typename to tell the compiler to parse it in a certain way. The Standard says at (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.

There are many names for which typename is not necessary, because the compiler can, with the applicable name lookup in the template definition, figure out how to parse a construct itself - for example with T *f;, when T is a type template parameter. But for t::x * f; to be a declaration, it must be written as typename t::x *f;. If you omit the keyword and the name is taken to be a non-type, but when instantiation finds it denotes a type, the usual error messages are emitted by the compiler. Sometimes, the error consequently is given at definition time:

// t::x is taken as non-type, but as an expression the following misses an
// operator between the two names or a semicolon separating them.
t::x f;

The syntax allows typename only before qualified names - it is therefor taken as granted that unqualified names are always known to refer to types if they do so.

A similar gotcha exists for names that denote templates, as hinted at by the introductory text.

The "template" keyword

Remember the initial quote above and how the Standard requires special handling for templates as well? Let's take the following innocent-looking example:

boost::function< int() > f;

It might look obvious to a human reader. Not so for the compiler. Imagine the following arbitrary definition of boost::function and f:

namespace boost { int function = 0; }
int main() {
int f = 0;
boost::function< int() > f;
}

That's actually a valid expression! It uses the less-than operator to compare boost::function against zero (int()), and then uses the greater-than operator to compare the resulting bool against f. However as you might well know, boost::function in real life is a template, so the compiler knows (14.2/3):

After name lookup (3.4) finds that a name is a template-name, if this name is followed by a <, the < is
always taken as the beginning of a template-argument-list and never as a name followed by the less-than
operator.

Now we are back to the same problem as with typename. What if we can't know yet whether the name is a template when parsing the code? We will need to insert template immediately before the template name, as specified by 14.2/4. This looks like:

t::template f<int>(); // call a function template

Template names can not only occur after a :: but also after a -> or . in a class member access. You need to insert the keyword there too:

this->template f<int>(); // call a function template

Dependencies

For the people that have thick Standardese books on their shelf and that want to know what exactly I was talking about, I'll talk a bit about how this is specified in the Standard.

In template declarations some constructs have different meanings depending on what template arguments you use to instantiate the template: Expressions may have different types or values, variables may have different types or function calls might end up calling different functions. Such constructs are generally said to depend on template parameters.

The Standard defines precisely the rules by whether a construct is dependent or not. It separates them into logically different groups: One catches types, another catches expressions. Expressions may depend by their value and/or their type. So we have, with typical examples appended:

  • Dependent types (e.g: a type template parameter T)
  • Value-dependent expressions (e.g: a non-type template parameter N)
  • Type-dependent expressions (e.g: a cast to a type template parameter (T)0)

Most of the rules are intuitive and are built up recursively: For example, a type constructed as T[N] is a dependent type if N is a value-dependent expression or T is a dependent type. The details of this can be read in section (14.6.2/1) for dependent types, (14.6.2.2) for type-dependent expressions and (14.6.2.3) for value-dependent expressions.

Dependent names

The Standard is a bit unclear about what exactly is a dependent name. On a simple read (you know, the principle of least surprise), all it defines as a dependent name is the special case for function names below. But since clearly T::x also needs to be looked up in the instantiation context, it also needs to be a dependent name (fortunately, as of mid C++14 the committee has started to look into how to fix this confusing definition).

To avoid this problem, I have resorted to a simple interpretation of the Standard text. Of all the constructs that denote dependent types or expressions, a subset of them represent names. Those names are therefore "dependent names". A name can take different forms - the Standard says:

A name is a use of an identifier (2.11), operator-function-id (13.5), conversion-function-id (12.3.2), or template-id (14.2) that denotes an entity or label (6.6.4, 6.1)

An identifier is just a plain sequence of characters / digits, while the next two are the operator + and operator type form. The last form is template-name <argument list>. All these are names, and by conventional use in the Standard, a name can also include qualifiers that say what namespace or class a name should be looked up in.

A value dependent expression 1 + N is not a name, but N is. The subset of all dependent constructs that are names is called dependent name. Function names, however, may have different meaning in different instantiations of a template, but unfortunately are not caught by this general rule.

Dependent function names

Not primarily a concern of this article, but still worth mentioning: Function names are an exception that are handled separately. An identifier function name is dependent not by itself, but by the type dependent argument expressions used in a call. In the example f((T)0), f is a dependent name. In the Standard, this is specified at (14.6.2/1).

Additional notes and examples

In enough cases we need both of typename and template. Your code should look like the following

template <typename T, typename Tail>
struct UnionNode : public Tail {
// ...
template<typename U> struct inUnion {
typedef typename Tail::template inUnion<U> dummy;
};
// ...
};

The keyword template doesn't always have to appear in the last part of a name. It can appear in the middle before a class name that's used as a scope, like in the following example

typename t::template iterator<int>::value_type v;

In some cases, the keywords are forbidden, as detailed below

  • On the name of a dependent base class you are not allowed to write typename. It's assumed that the name given is a class type name. This is true for both names in the base-class list and the constructor initializer list:

     template <typename T>
    struct derive_from_Has_type : /* typename */ SomeBase<T>::type
    { };
  • In using-declarations it's not possible to use template after the last ::, and the C++ committee said not to work on a solution.

     template <typename T>
    struct derive_from_Has_type : SomeBase<T> {
    using SomeBase<T>::template type; // error
    using typename SomeBase<T>::type; // typename *is* allowed
    };


Related Topics



Leave a reply



Submit