4

There are a lot of questions at this site with the problems while compiling c++ template code. One of the most common solutions to such problems is to add typename (and, less frequently, template) keyword in the right places of the program code:

template<typename T>
class Base
{
public:

    typedef char SomeType;

    template<typename U>
    void SomeMethod(SomeType& v)
    {
        // ...
    }

};

template<typename T>
class Derived : public Base<T>
{
public:

    void Method()
    {
        typename Base<T>::SomeType x;
    //  ^^^^^^^^

        this->template SomeMethod<int>(x);
    //        ^^^^^^^^
    }
};

Whether there is a code that compiles both with and without keyword typename and gives different results (e.g. output strings)? Similar question for template keyword.

If not, whether these keywords are really necessary in such meanings?

A small overview of the current situation

@Paul Evans wrote a good answer but it is more suitable for the question "Where and why do I have to put the “template” and “typename” keywords?", not for my question.

@Simple gave an example of the required code for typename keyword and its possible variation. @Jarod42 gave another variation without any templates, which is probably a gcc bug because it does not compile with clang.

@n.m. gave an example of the required code for template keyword, @dyp improved it. @n.m. also wrote the another code for both keywords using SFINAE.

@James Kanze in his answer argues that it is impossible to write the required code and any attempts to do it will result in undefined behavior. So the above examples of code are illegal.

It is interesting to find out who is right and what the C++ standard says about this.

Community
  • 1
  • 1
Constructor
  • 7,273
  • 2
  • 24
  • 66
  • 1
    Maybe read up about these keywords beforehand? They are related to name lookup and dont have a semantically meaning. – Sebastian Hoffmann Feb 27 '14 at 13:27
  • 2
    Consider `f < 5 > (25);`. How is this parsed? It could be some weird comparison `(f>5) > 25` or a function call `f<5> (25)`. Similarly, `X::m * p;` could be a declaration (of `p`) where `X::m` is a type, or it could be an expression involving a static data member `X::m` times some previously declared `p`. – dyp Feb 27 '14 at 13:28
  • 5
    http://ideone.com/ewfn0Q – Simple Feb 27 '14 at 13:28
  • @Simple You could even write `auto x = B::bar(10);` vs. `auto x = typename B::bar(10);`. – dyp Feb 27 '14 at 13:31
  • @Paranaix Possibly my question is silly enough. And of course I know what are they used for. – Constructor Feb 27 '14 at 13:31
  • @dyp Yes, I know what the problems compiler is experienced without these keywords while parsing c++ code. – Constructor Feb 27 '14 at 13:34
  • @Simple Greate! And what about `template` keyword? – Constructor Feb 27 '14 at 13:34
  • 1
    @Simple thats nice - pull it into this –  Feb 27 '14 at 13:37
  • It's harder to come up with a similar example for `template`. – Simple Feb 27 '14 at 13:42
  • @Simple Except that that is illegal code (resulting in undefined behavior). When you write `typename B::bar`, the compiler assumes that `bar` names a type, but when you instantiate the template, `bar` names a function; the `struct bar` should _not_ be found by the lookup. – James Kanze Feb 27 '14 at 13:50
  • @Simple Please, post your code as an answer. – Constructor Feb 27 '14 at 13:52
  • 1
    @JamesKanze http://ideone.com/XiWlXs better? – Simple Feb 27 '14 at 14:01
  • 3
    http://ideone.com/UIqrtb Feel free to improve. – n. m. could be an AI Feb 27 '14 at 14:05
  • @Simple It suffers from exactly the same problem. By definition, it is impossible to create a program that would be legal both with and without the `typename`, and have different, but defined semantics in both cases; it is perfectly legal (but not desirable) for a compiler to defer parsing the template until instantiation, and to totally ignore the `typename` or `template`. If this would result in something different than a compiler which actively used them, you have undefined behavior. – James Kanze Feb 27 '14 at 14:10
  • @JamesKanze: what about http://ideone.com/iuq0AT ? There is no template. – Jarod42 Feb 27 '14 at 14:20
  • 2
    @n.m. Without any `reinterpret_cast`s: http://coliru.stacked-crooked.com/a/a051325f703b097c – dyp Feb 27 '14 at 14:21
  • @Jarod42 *main.cpp:11:22: error: typename specifier refers to non-type member 'baz' in 'widget'* http://coliru.stacked-crooked.com/a/fe4ff0bf6c9eefeb – dyp Feb 27 '14 at 14:22
  • Does the example with template is valid ? According to @JamesKanze's answer, it should not be... – Jarod42 Feb 27 '14 at 14:28
  • @n.m. Interesting code, thank you. – Constructor Feb 27 '14 at 14:31
  • @Jarod42 What example did you mean? – Constructor Feb 27 '14 at 15:07
  • @Constructor: I mean the [dyp's one](http://coliru.stacked-crooked.com/a/a051325f703b097c) for example (with the keyword `template`). – Jarod42 Feb 27 '14 at 15:12
  • @JamesKanze even if the examples provided are invalid, there's another class of examples: those that involve SFINAE. In this case your argument doesn't work. – n. m. could be an AI Feb 27 '14 at 15:16
  • @Jarod42 Clearly, thanks. I want to know JamesKanze is right or not, too. – Constructor Feb 27 '14 at 15:18
  • @n.m. Can you give such examples (using SFINAE), please? – Constructor Feb 27 '14 at 15:19
  • 1
    @Constructor http://ideone.com/mEhajk g++ does not accept one of the calls (commented out in the code), but clang++ does. I thing g++ is in the wrong here. Anyway the rest of the calls look pretty much valid. – n. m. could be an AI Feb 27 '14 at 16:27
  • @n.m. Brilliantly! Thank you. I think this code could refute James Kanze's point of view. – Constructor Feb 27 '14 at 16:49
  • @n.m. Ah! It's entirely possible that there could be something involving SFINAE; I've not studied it in detail. But maybe. I suppose it depends on how you interpret "the specified member is not a type where a type is required"; is a type required because the name was qualified by `typename`? (I think the undefined behavior occurs before the compiler gets here, but it's really not very clear.) – James Kanze Feb 27 '14 at 17:50
  • @n.m. The example is very good. I'm not sure what to think about it, however: undefined behavior, or required behavior corresponding to that of clang? I think you can read the standard two ways. – James Kanze Feb 27 '14 at 17:53
  • Re the summary: there is no doubt that the examples in the question here are undefined behavior. The one involving SFINAE, on the other hand? I think the standard is ambiguous in its regard; one could interpret it either way. – James Kanze Feb 27 '14 at 17:55
  • @JamesKanze What parts of the standard do you mean? – Constructor Feb 27 '14 at 18:02
  • I think that passing object to variadic function is UB, though (in the SFINAE example).. (@Constructor: comment move correctly, and variadic function are functions with `...` (as `printf`)). – Jarod42 Feb 27 '14 at 18:13
  • @Jarod42 I know what variadic functions are. :-) As I understand your previous comment got wrong place and it seemed very strange to me. – Constructor Feb 27 '14 at 18:20
  • @Jarod42 The code can be simply corrected to prevent UB. It is sufficient that the nonvariadic variant of function would take a pointer rather than a value (as its second argument). And pass something like `(S*)nullptr` or `(S*)0` instead of `S()`. – Constructor Feb 27 '14 at 18:51
  • You might be interested in my comments on @JamesKanze's answer – Johannes Schaub - litb Feb 27 '14 at 18:53
  • @JamesKanze why is UB involved, because you say "I think the undefined behavior occurs before the compiler gets here, but it's really not very clear."? – Johannes Schaub - litb Feb 27 '14 at 18:55
  • @JohannesSchaub-litb Interesting information, thank you. – Constructor Feb 27 '14 at 18:58
  • @james The text that says "the specified member is not a type where a type is required" is in a note and has no real significance. – Johannes Schaub - litb Feb 27 '14 at 19:04
  • @JohannesSchaub-litb I'm not too sure myself. If you have `typename A::B` in the template (where `A` is a template parameter), and when you instantiate, `B` does _not_ name a type, the program is ill formed. This is not an error ignored by SFINAE. On thinking it over, however... If substitution failure occurs, the template is not instantiated, so what happens when you instantiate can't be an issue. – James Kanze Feb 27 '14 at 19:15
  • @JamesKanze what do you mean by "error ignored by SFINAE"? A type that is ill-formed when written using the substituted template arguments causes deduction to fail and triggers the "SFINAE case", not a hard compiler error. And the `typename A::B` case certainly looks like such an "SFINAE case" to me. I see no difference at all to the case where `B` doesn't exist at all. In both cases we have an error and trigger the SFINAE case. – Johannes Schaub - litb Feb 27 '14 at 19:19
  • I agree that "If a specialization of a template is instantiated for a set of template-arguments such that..." requires an instantiation, but SFINAE prevents such. But therefor the Standard says "An invalid type or expression is one that **would** be ill-formed...", so the SFINAE can try to see whether the instantiation would work and use the rules governing it, without actually doing it. – Johannes Schaub - litb Feb 27 '14 at 19:23
  • @JohannesSchaub-litb That's basically what I said, in the end. My initial analysis was a bit different, but I've changed my mind about it. – James Kanze Feb 28 '14 at 09:17

2 Answers2

6

The rule is: typename has to be used whenever a name that depends on a template parameter is a type. There are clear cases where it's needed, consider

template <typename T> 
class Foo { 
    typename T::type * p; 
    //... 
}; 

Here, the second typename is used to indicate that type is a type defined within class T. Thus, p is a pointer to the type T::type.

Without typename, type would be considered a member of class T. So the expression:

T::type * p

would be a multiplication of the type member of class T with p.

Similarly, the rule is: .template, ->template or ::template must be used when accessing a template member that uses a template parameter. Consider:

 p->template SomeMethod<int>(x);

without the use of template, the compiler does not know that the < token is not less-than but the start of a template argument list.

Paul Evans
  • 27,315
  • 3
  • 37
  • 54
  • and what about the template? – 4pie0 Feb 27 '14 at 13:42
  • Unfortunately, it is not the answer to my question. See the code which @Simple gave in the comments of the question. – Constructor Feb 27 '14 at 13:50
  • Sometimes you even need both, like `typename widget::template apply`. – Simple Feb 27 '14 at 13:54
  • I think the answer is complete and should be accepted – 4pie0 Feb 27 '14 at 13:58
  • @piotruś It is the complete answer, but not for _my_ question. – Constructor Feb 27 '14 at 13:59
  • @Constructor please explain what it lacks or what is unclear yet, and maybe author will enhance it – 4pie0 Feb 27 '14 at 14:02
  • @piotruś As I wrote this answer is good and complete enough. But it corresponds to the response to the question "Where keywords `typename` and `template` are needed to be used?" I know where. My question was different. See the code which @Simple gave in the comments to the question to understand what I really want. – Constructor Feb 27 '14 at 14:12
  • Interesting. But how is this different from the non-template case? I.e., if Foo is a type, "Foo::type * p;" is OK, but if T is a typename template, "T::type * p;" requires the "template" keyword to remove an ambiguity? – Igor ostrovsky Mar 03 '14 at 19:24
  • @Igorostrovsky because the compiler *knows* all about Foo and therefore all of its members. Where as T is a placeholder of a yet-to-be determined type. – Paul Evans Mar 09 '14 at 10:27
2

By definition, it is impossible to write code which differs in meaning with or without the keyword; any attempt to do so will result in undefined behavior. The only purpose of these keywords (at least in this context) is to allow the compiler to fully parse the template before instantiation: in order to correctly parse C++, the compiler must know whether a symbol designates a type, a template or something else.

Once you instantiate the template, the compiler no longer really needs the keywords; they have no impact on name lookup, or anything else. The only particularity is that if the name found puts a lie to your declaration (you said type, and in the instantiation, it isn't a type), undefined behavior occurs. If, for example, the compiler has stored the template in the form of a parse tree, this parse tree will be incorrect, and who knows what that might imply.

I would expect that most good compilers would note the category in the first parse, and if name lookup returns something else, emit an error, but for historical reasons, I suspect that there are still compilers which more or less ignore the template or typename in this context, treating it as a comment; store the template as a sequence of tokens, and only parse once the template is instantiated, using the categories it actually finds in the instantiation.

EDIT:

I've been rereading parts of the standard, and I'm no longer sure that there is undefined behavior. C++11, at least, says:

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.

When a qualified-id is intended to refer to a type that is not a member of the current instantiation and its nested-name-specifier refers to a dependent type, it shall be prefixed by the keyword typename, forming a typename-specifier. If the qualified-id in a typename-specifier does not denote a type, the program is ill-formed.

Ill-formed usually (but not always) requires a diagnostic. (As mentioned above, I would expect a compiler to issue a diagnostic in any case.)

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • Can you support your words with quotations from standard? Why the codes of Simple, n.m are not right in accordance with standard? Thank you. – Constructor Feb 27 '14 at 14:30
  • Both clang++ and g++ do something else. They apparently parse the template, store the name category, and when an instantiation is made, search for the name only within its associated category. If e.g. it was `typename x` and in the actual instantiation there are both a type member and a non-type member named `x`, the type member is taken, even if in the non-template case the non-type one would be taken. It is not clear to me whether the standard sanctions such behaviour or not. – n. m. could be an AI Feb 27 '14 at 16:34
  • @n.m. Well, if you lied, it's undefined behavior, so whatever the compiler does is "correct". – James Kanze Feb 27 '14 at 17:56
  • As far as I know, clang correctly finds the non-type name even with `typename` (so, it indeed has no impact on name lookup for clang, unlike `class`). GCC doesn't, and it is because of this bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48920 . I don't think it is undefined behavior in the non-template case. And in the template case, I think it is an SFINAE-case in SFINAE contexts, so compilers can't just ignore the rules. – Johannes Schaub - litb Feb 27 '14 at 18:49
  • @JohannesSchaub-litb Yes. I hadn't thought about the context of SFINAE. I'm not sure what the implications are, because I'm not sure of the order of the different steps the compiler is required to take. Finding a non-type when something is declared with a `typename` isn't one of the errors which SFINAE ignores (or at least, it's not in the list). On the other hand, finding a non-type means that the instantiation fails, so the template won't be instantiated (and if it isn't instantiated, there can't be a mismatch between the instantiation and the template). – James Kanze Feb 27 '14 at 19:09
  • @Constructor The whole issue is interesting. I don't find the standard particularly easy to understand here, and I'm curious as to how it should be interpreted. – James Kanze Feb 27 '14 at 19:18