template<class T> class foo {
struct i { // Some internal structure
T val;
};
i* bar();
};
template<class T> foo<T>::i* foo<T>::bar() {
// Return a type i*
}
typename confusion
The use of the typename qualifier still confuses me sometimes. For example, why can't the compiler deduce the return argument in this situation:
Is it because foo<T> has not yet been defined so the compiler doesn't know whether i* is a function pointer, a type, another template, etc...?
Edit: fixed code spacing.
It's because the structure T is dependent on the template argument T. If you instead had:
Then there would be no problems with typename because i doesn't depend on a template argument.
template<class T> class foo { struct i { // Some internal structure int val; }; i* bar();};
Then there would be no problems with typename because i doesn't depend on a template argument.
Quote:Original post by CTar
It's because the structure T is dependent on the template argument T. If you instead had:template<class T> class foo { struct i { // Some internal structure int val; }; i* bar();};
Then there would be no problems with typename because i doesn't depend on a template argument.
But then shouldn't the foo<T>:: scope resolution take care of that?
I'm not sure, but it appears that the code is trying to create a class-data structure hybrid template. I don't think this is valid. (although i'm probably wrong)
what exactly are you trying to do?
what exactly are you trying to do?
I'm just trying to return types that are declared in my template. This would not work either:
template<class T> class foo { enum i{red, black}; i bar();};template<class T> foo<T>::i foo<T>::bar() { // return type i}
Quote:Original post by Absolution
I'm just trying to return types that are declared in my template. This would not work either:
*** Source Snippet Removed ***
That's because i is dependent on T, you could partially specialize another foo, like this:
template<class T> class foo { enum i{red, black}; i bar();};template<class T> foo<T>::i foo<T>::bar() { // return type i}template<> class foo<int>{ enum i{blue,green,white};};
As you can see i is dependent on the template argument. This mean you need to use typename, since i is an dependent identifier. So the correct thing to do would be this:
template<class T> class foo { struct i { // Some internal structure T val; }; i* bar();};template<class T> typename foo<T>::i* foo<T>::bar() { // Return a type i*}
--------------
template<class T> class foo { enum i{red, black}; i bar();};template<class T> typename foo<T>::i foo<T>::bar() { // return type i}
All this stuff with dependent expressions, types and identifiers is quite complicated and I suggest you read section 14.6 of the standard.
You may also check out MSDN for a shorter reading on dependent types and templates:
http://msdn.microsoft.com/en-us/library/19cbwccf.aspx
http://msdn.microsoft.com/en-us/library/19cbwccf.aspx
I'd like to post some related quotations from the C++ standard (section 14.6):
Emphasis added, this is your problem, the type isn't being examined.
Quote:14.6.2 Dependent names [temp.dep]
Inside a template, some constructs have semantics which may differ from one instantiation to another. Such a construct depends on the template parameters. In particular, types and expressions may depend on the type and/or value of template parameters (as determined by the template arguments) and this determines the context for name lookup for certain names. Expressions may be type-dependent (on the type of a template parameter) or value-dependent (on the value of a non-type template parameter).
Quote:In the definition of a class template or a member of a class template, if a base class of the class template depends on a template-parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member.
Emphasis added, this is your problem, the type isn't being examined.
Quote:14.6.2.1 Dependent types [temp.dep.type]
A type is dependent if it is
— a template parameter,
— a qualified-id with a nested-name-specifier which contains a class-name that names a dependent type or whose unqualified-id names a dependent type,
— 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.
Quote:Original post by Absolution
I'm just trying to return types that are declared in my template.
struct foo{ static int i;};struct bar{ typedef int i;};
foo::i is a static member.
bar::i is a nested type.
With non-dependent names, the compiler can easily determine what situation it is in. This isn't the case with dependent names. And yet, templates must be syntax-checked before they actually are instanciated. So the compiler will assume that Foo::Bar refers to a static member unless you explicitely tell it it is a type by writing typename Foo::Bar.
The problem in your case isn't that the compiler cannot deduce the return type, it is that it thinks you are using a static variable where a type is expected. i.e. that you have a syntax error in your code.
Thanks Fruny, I think I get it. I'm not 100%, but I'm almost there.
Since the template hasn't been instantiated yet, the compiler has no way of determining whether the dependent name Foo::Bar is a type or not and it defaults to assuming it is not, which would be a syntax error because it means I'm trying to specify a static member variable as a return type. In other words, the compiler hasn't created a class out of template Foo yet, so it has no way to check that Foo:Bar is an enum I declared in the class. It's getting stuck at the basic syntax stage.
In the same way, if in main I tried to do something like this:
Foo::Bar tmp = Foo::black;
the compiler would assume that Foo::Bar is a static member, which is the same as:
static int i tmp = Foo::black;
which is a syntax error.
Edit: For the second example.
Since the template hasn't been instantiated yet, the compiler has no way of determining whether the dependent name Foo::Bar is a type or not and it defaults to assuming it is not, which would be a syntax error because it means I'm trying to specify a static member variable as a return type. In other words, the compiler hasn't created a class out of template Foo yet, so it has no way to check that Foo:Bar is an enum I declared in the class. It's getting stuck at the basic syntax stage.
In the same way, if in main I tried to do something like this:
Foo::Bar tmp = Foo::black;
the compiler would assume that Foo::Bar is a static member, which is the same as:
static int i tmp = Foo::black;
which is a syntax error.
Edit: For the second example.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement