Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

It had been a while since GCC caught me with this one, but it just happened today. But I've never understood why GCC requires typedef typename within templates, while VS and I guess ICC don't. Is the typedef typename thing a "bug" or an overstrict standard, or something that is left up to the compiler writers?

For those who don't know what I mean here is a sample:

template<typename KEY, typename VALUE> bool find(const std::map<KEY,VALUE>& container, const KEY& key) {     std::map<KEY,VALUE>::const_iterator iter = container.find(key);     return iter!=container.end(); } 

The above code compiles in VS (and probably in ICC), but fails in GCC because it wants it like this:

template<typename KEY, typename VALUE> bool find(const std::map<KEY,VALUE>& container, const KEY& key) {     typedef typename std::map<KEY,VALUE>::const_iterator iterator; //typedef typename     iterator iter = container.find(key);     return iter!=container.end(); } 

Note: This is not an actual function I'm using, but just something silly that demonstrates the problem.

like image 829
Robert Gould Avatar asked Mar 13 '09 11:03

Robert Gould


People also ask

What is Typedef Typename?

typedef is defining a new type for use in your code, like a shorthand. typedef typename _MyBase::value_type value_type; value_type v; //use v. typename here is letting the compiler know that value_type is a type and not a static member of _MyBase . the :: is the scope of the type.

Why do we need Typename C++?

In general, C++ needs typename because of the unfortunate syntax [*] it inherits from C, that makes it impossible without non-local information to say -- for example -- in A * B; whether A names a type (in which case this is a declaration of B as a pointer to it) or not (in which case this is a multiplication ...


1 Answers

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.

like image 154
David Rodríguez - dribeas Avatar answered Oct 16 '22 01:10

David Rodríguez - dribeas