Click here to Skip to main content
Click here to Skip to main content

Tagged as

Dependant Name Hell

, 21 Jul 2011 CPOL
Rate this:
Please Sign up or sign in to vote.
When to use the typename keyword to identify dependent types, and when not to.

Introduction

This article is targeted at those interested in C++ templates and have already made some experiences with them.

The attached code sample was tested in VC++ 2008 SP1 and GCC (MinGW) 4.5.2. A VS2008 workspace and a batch file "compile.bat" for compiling the code sample in GCC is included.

The code sample does not produce an application, it is only intended to show the reaction of the compiler on certain code sequences. By default, there should be no compiler errors. Certain definitions can be enabled (e.g., BAD_PRACTICE_1A) to show the compiler's reaction on certain non C++ standard compliant code. All samples are explained in the following article.

The topics contained in this article refer to my experiences when correcting the code from my CodeProject article "Enumerator Lists and Enumerated Arrays" in order to compile using GCC. I do not intend to give a full review about non-standard compliant behavior of VC++ 2008 concerning templates, this is just a summary of topics that occurred to me. They might be helpful when creating portable C++ code.

It is important to understand that each C++ compiler represents a different "C++ dialect". Therefore it is possible to slide into coding practices that are not standard-compliant and also not recognized by other compilers.

Background

warning C4346: '...' : dependent name is not a type

When writing my article Enumerator Lists and Enumerated Arrays I got that a lot. And after the warning, there always was an error of some sort. Using MSDN help, I quickly figured I was missing a typename and added that whenever in doubt. Finally, I ended up doing things like this (okay, the example is exaggerated):

template<typename t>
struct a {
    typename int x;
};

This is OK by Visual C++ 2008 standards (independent of setting the \za compiler flag which disables Microsoft language extensions). Anyway, the code is not portable. The int type is not dependent and should not be declared as such. When I tried to compile my project with GCC (MinGW), I got plenty of compiler errors such as:

error: expected nested-name-specifier before '...'

Well, great! Let's try and see what it is all about dependent type names.

What is a dependent name?

On open-std.org, I found the following definition [1]:

A type is dependent if it is:

  • a template parameter,
  • a member of an unknown specialization,
  • a cv-qualified type where the cv-unqualified type is dependent,
  • a compound type constructed from any dependent type,
  • an array type constructed from any dependent type or whose size is specified by a constant expression that is value-dependent,
  • a template-id in which either the template name is a template parameter or any of the template arguments is a dependent type or an expression that is type-dependent or value-dependent.

[Note: Because typedefs do not introduce new types, but instead simply refer to other types, a name that refers to a typedef that is a member of the current instantiation is dependent only if the type referred to is dependent.]

This actually defines the term "dependent type", not "dependent name". For the latter, I found the following definitions:

  • IBM: A dependent name is a name that depends on the type or the value of a template parameter [2]. (Actually, here the fact is missed that the template parameter is also a dependent name.)
  • Microsoft: Names that depend in some way on the template arguments, referred to as dependent names[3].

As a result, dependent names may refer to dependent types, but may also to something else.

C++ Standard: A name is a use of an identifier that denotes an entity or label. Every name that denotes an entity is introduced by a declaration.[4].

Names therefore refer to probably anything created by the programmer. E.g., variables, classes, functions, and namespaces are referred to by variable names, class names, function names, and namespace names.

So, when do we have to use typename to declare dependent types?

The following sample comprises some possible contents of a class template:

template<typename t>
struct a {
    t x; // t is a dependent type that has already been identified
    // as a type
    
    typedef typename t::value_type value_type; // As value_type is a 
    // dependent type it must be prefixed
    
    value_type v; // As an alias, value_type already is 
    // identified as a typename
       
    int i; // int is not a dependent type at all
    
    void f() {
        t::value = 5; // Now t::value is a static data member
        t::f(); // f is a dependent name, but of a static method
    }
};

Generally speaking, when the compiler does not know that a dependent name refers to a type but we want to use it as such. Consider the following rules of thumb:

  • When coming across a dependent name, it first assumes it as anything else but a type. It is necessary to prefix it by typename.
  • When writing a :: inside a template, look if the names left of it refer to at least one dependent name. If that is the case and the name right to it also refers to a type, typename is needed.
  • If the name has already been identified as a type in the template, do not use typename again on it (see types t and value_type in the previous example).
  • Get a second opinion from another compiler. Visual C++ nowadays claims to be mostly standard-compliant. However, as seen, it not only compiles a sub-set of the standard, but also non-compliant code.

The whole issue revolves around two topics:

  • When a C++ compiler parses a class template, it already performs syntax-checking. Namespaces are resolved, types and values are separated, etc. It is ensured that it would be possible to instantiate the template with some template parameters. Or at least it should be.
  • Being able to use the template with another compiler is the other thing.

What else is out there (related to dependent names)?

Actually a lot. I came around the following issues in my project:

VC++ allows dependent types to be specified without typename

Before VS2003, VC++ did not require dependent types to be specified at all [5]. (VS2008) VC++ still sometimes does not require the typename keyword where it is necessary [6].

The following example provides a function template where normally the same rules would be applied as in class templates. It compiles in VC++ 2008 without the typename as well (the same effect applies to methods within class templates).

namespace example2 
{
    template <typename T>
    void f(const T& obj)
    {
    #ifdef BAD_PRACTICE_2
        for (T::const_iterator i = obj.begin(); i != obj.end(); i++) {
    #else
        for (typename T::const_iterator i = obj.begin(); i != obj.end(); i++) {
    #endif
            // ...
        }
    }
}

In GCC 4.5.2, the following error is emitted:

In function '...':
error: need 'typename' before '...' because '...' is a dependent scope
... 

Calling the explicit instantiation of a static function template in a class template from another template

Huh, that was long. Look at the following example:

namespace example3 
{
    template<typename t> // The class template
    struct a {
        template<typename t2> // The static function template inside
        static void af(t2 i) {
            i *= 2;
        }
    };

    template<typename t>
    void f() {
        a<t>::af(0); // ok, af<...>(...) will be instantiated along with 
        // a<...> 
        
    #ifdef BAD_PRACTICE_3
        a<t>::af<int>(0); 
    #else 
        a<t>::template af<int>(0); // a<...>::f is a dependent name
        // but already specialized. It is necessary to tell the 
        // compiler that af<...> is a template otherwise name lookup
        // may fail.
    #endif
    }
}

Again, this sample compiles in VC++ 2008, but GCC 4.5.2 will emit the following error:

In function '...':
error: expected primary-expression before '...'
...

Template namespace resolution in function templates

The following code sample will compile in VC++ 2008. The critical line is a<t> aa;. At this code position, it should not be possible to resolve a as it is contained in namespace example4a which is not introduced into the declarative region at this point. It seems that VC++ compiles the contents of example4b::f() with the namespace resolution at the time the function is instantiated. The namespace inclusion for example4a is available at the point of instantiation but not when the function template is defined.

namespace example4 
{
    namespace example4a 
    {
        template<typename t>
        struct a {
            t value;
        };
    } 

    namespace example4b 
    {
        template<typename t>
        void f() {
    #ifdef BAD_PRACTICE_4
            a<t> aa;
    #else
            example4a::a<t> aa;
    #endif
            aa.value = 5;
        }
    } 

    #ifdef BAD_PRACTICE_4
    using namespace example4a;
    #endif

    void f() {
        example4b::f<int>();
    }
}

In GCC 4.5.2, the following error will be emitted when compiling BAD_PRACTICE_4:

In function '...':
error: '...' was not declared in this scope
... 

Compiler-specific extensions

Probably each compiler has some intentional extensions to the C++-standard that can be toggled via compiler switches [7]. When creating a C++ project in VS2008, these extensions are automatically turned on and can be toggled via the project settings > C/C++ > "Language" > "Disable language extensions". Changes may not be restricted to documented features, but may affect other behavior as well.

The following sample class template provides a typedef that is referenced in the sub-class template. typedef declarations are normally not visible in sub-classes. The name of this beast is Why am I getting errors when my template-derived-class uses a nested type it inherits from its template-base-class? [8]

namespace example5 
{
    template<typename t>
    class base {
    public:
        typedef t value_type;
    };
    
    template<typename t>
    class derived : public base<t> {
#ifdef BAD_PRACTICE_5
        value_type my_int;
#else
        typename base<t>::value_type my_int;
#endif       
    };
}

GCC's reaction to this is:

error: '...' does not name a type
...

Looking at [8], you might wonder if VC++ 2008 would accept the following:

#ifdef BAD_PRACTICE_5
    base<t>::value_type my_int;
#else

Have a guess Wink | ;)

References

I intentionally don't give links here. Links may change. Google search results adapt.

  1. open-std.org: Definition of Dependent Name - Revision 2
  2. IBM XL C/C++ V8.0 for AIX: Name binding and dependent names (C++ only)
  3. MSDN: Templates and Name Resolution
  4. Standard for Programming Language C++
  5. MSDN: Visual C++ .NET 2003 Summary of Compile-Time Breaking Changes
  6. StackOverflow: Visual C Compiler allows Dependent Name as a Type Without Typename
  7. MSDN: Microsoft Extensions to C and C++
  8. Parashift.com C++ FAQ Lite: [35.18] Why am I getting errors when my template-derived-class uses a nested type it inherits from its template-base-class?

History

  • 2011/07/18: Original version.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Doc Lobster
Software Developer
Germany Germany
No Biography provided

Comments and Discussions

 
GeneralMy vote of 5 PinmemberPablo Aliskevicius25-Jul-11 21:35 
GeneralRe: My vote of 5 PinmemberDoc Lobster26-Jul-11 3:05 
Generaljust one doubt for author and editors PinmemberEmilio Garavaglia21-Jul-11 22:31 
GeneralRe: just one doubt for author and editors PinmemberDoc Lobster22-Jul-11 0:12 
GeneralRe: just one doubt for author and editors PinmemberAlain Rist4-Aug-11 10:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141223.1 | Last Updated 21 Jul 2011
Article Copyright 2011 by Doc Lobster
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid