typedef with templates - c++

template<class T> struct A {
typedef int Int;
A::Int b; // Line 1 (fails)
Int c; // Line 2 (compiles)
};
int main(){
A<int> x;
x.c = 13;
}
Errors
error: ISO C++ forbids declaration of ‘Int’ with no type
error: extra qualification ‘A<T>::’ on member ‘Int’
error: expected ‘;’ before ‘b’
Line 1 fails but Line 2 compiles. Why?

You need a typename
typename A::Int b;
The typename keyword is required because the member is referred to using a qualified name A::Int.
Int c is fine because no qualified name is used in that case.
14.6/6
Within the definition of a class template or within the definition of a member of a class template, the keyword typename is not required when referring to the unqualified name of a previously declared member
of the class template that declares a type. The keyword typename shall always be specified when the
member is referred to using a qualified name, even if the qualifier is simply the class template name.

Related

Is a typedef to self allowed over template parameters [duplicate]

This question already has answers here:
In a C++ template class, can I typedef the template parameter using the same name?
(2 answers)
Closed 1 year ago.
I was reading someone else's code when I came across this piece (stripped to MWE):
template<typename R> class Test {
public:
typedef R R;
};
Here there is a typedef of the template parameter to itself, and it made GCC and clang (with or without -std=c++2a) complain:
test.cc:3:19: error: declaration of 'typedef R Test::R' shadows template parameter
However, ICC and MSVC on Compiler Explorer both accept that piece.
I've read this question, and it is suggested that a typedef to self is usually a no-op. However, here it does not seem to be the case. I've also found this question to be related but I think they should be different since here we are using a typedef.
So here is the question:
Is this kind of redefinition allowed by the standard?
Are there any side effects of that statement? Why might one write that?
No. The name of a template parameter is not allowed to be redeclared.
The name of a template parameter is not allowed to be redeclared
within its scope (including nested scopes). A template parameter is
not allowed to have the same name as the template name.
template<class T, int N>
class Y {
int T; // error: template parameter redeclared
void f()
{
char T; // error: template parameter redeclared
}
};
template<class X> class X; // error: template parameter redeclared
From the standard, [temp.local]/6:
The name of a template-parameter shall not be bound to any following
declaration contained by the scope to which the template-parameter
belongs. [Example 5:
template<class T, int i> class Y {
int T; // error: template-parameter hidden
void f() {
char T; // error: template-parameter hidden
}
friend void T(); // OK: no name bound
};
template<class X> class X; // error: hidden by template-parameter
— end example]

Don't understand behavior of g++-4.8 [duplicate]

This doesn't compile:
template<class X> struct A {
template<int I> void f() {}
};
template<class T> void g()
{
A<T> a;
a.f<3>(); // Compilation fails here (Line 18)
}
int main(int argc, char *argv[])
{
g<int>(); // Line 23
}
The compiler (gcc) says:
hhh.cpp: In function 'void g()':
hhh.cpp:18: error: expected primary-expression before ')' token
hhh.cpp: In function 'void g() [with T = int]':
hhh.cpp:23: instantiated from here
hhh.cpp:18: error: invalid use of member (did you forget the '&' ?)
Can anyone explain why this is? Is there a way to get it to work?
Try the following code:
template<class T> void g()
{
A<T> a;
a.template f<3>(); // add `template` keyword here
}
According to C++'03 Standard 14.2/4:
When the name of a member template specialization appears after . or -> in a postfix-expression, or after nested-name-specifier in a qualified-id, and the postfix-expression or qualified-id explicitly depends on a template-parameter (14.6.2), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.
Future C++ Standard seems to be still require this keyword according to draft n2857 14.3/4. Some compilers has special mode that allows to compile original code without errors (Comeau compiles it in so called relaxed mode).

Is it allowed to typedef a class template type argument into the same name?

This seems to compile and even work as expected in MSVC. But is it legal C++ code and is it guaranteed to do what is expected here (that is, export the template type to the struct's users under the same name)?
template <typename EnumType>
struct Enum
{
// There are two hard problems in CS: cache invalidation and naming things.
typedef EnumType EnumType;
};
I think the type definition is not allowed.
14.6.1 Locally declared names (N4296)
6 A template-parameter shall not be redeclared within its scope
(including nested scopes).A template-parameter shall not have the same name as
the template name. [ Example:
template<class T, int i> class Y {
int T; // error: template-parameter redeclared
void f() {
char T; // error: template-parameter redeclared
}
};
template<class X> class X; // error: template-parameter redeclared
— end example ]
The typedef EnumType EnumType is a redefinition of the template-parameter as typedef-name.

Vector of pointers to struct

Following program looks pretty OK to me. But I can not get it compiled.
#include <iostream>
#include <vector>
using namespace std;
int main()
{
struct a
{
int i;
int j;
};
std::vector<a*> vecA;
a* pA = new a;
pA->i = 4;
pA->j = 9;
vecA.push_back(pA);
return 0;
}
It generates following error.
struct_update.cc: In function ‘int main()’:
struct_update.cc:32:19: error: template argument for ‘template<class _Alloc> class std::allocator’ uses local type ‘main()::a*’
struct_update.cc:32:19: error: trying to instantiate ‘template<class _Alloc> class std::allocator’
struct_update.cc:32:19: error: template argument 2 is invalid
struct_update.cc:32:25: error: invalid type in declaration before ‘;’ token
struct_update.cc:39:10: error: request for member ‘push_back’ in ‘vecA’, which is of non-class type ‘int’
This isn't true anymore in the new C++11 standard, but current compilers don't fully implement it yet.
A local type can't be a template parameter. Move your structure definition above main, and everything will work.
Or update your compiler to one that supports this part of C++11.
Here's the restriction from C++03 section 14.3.1 ([temp.arg.type]), which is removed in C++11:
A local type, a type with no linkage, an unnamed type or a type compounded from any of these types shall not be used as a template-argument for a template type-parameter.
Move the structure definition out of main function.
struct a
{
int i;
int j;
};
int main()
{
std::vector<a*> vecA;
a* pA = new a;
pA->i = 4;
pA->j = 9;
vecA.push_back(pA);
In C++03 you cannot do this
A local type, a type with no linkage, an unnamed type or a type compounded from any of these types shall not be used as a template-argument for a template type-parameter.
In C++11 i think you can according to the standard. Even though my Visual Studio 11 compiler refuses to allow it

template member function of template class called from template function

This doesn't compile:
template<class X> struct A {
template<int I> void f() {}
};
template<class T> void g()
{
A<T> a;
a.f<3>(); // Compilation fails here (Line 18)
}
int main(int argc, char *argv[])
{
g<int>(); // Line 23
}
The compiler (gcc) says:
hhh.cpp: In function 'void g()':
hhh.cpp:18: error: expected primary-expression before ')' token
hhh.cpp: In function 'void g() [with T = int]':
hhh.cpp:23: instantiated from here
hhh.cpp:18: error: invalid use of member (did you forget the '&' ?)
Can anyone explain why this is? Is there a way to get it to work?
Try the following code:
template<class T> void g()
{
A<T> a;
a.template f<3>(); // add `template` keyword here
}
According to C++'03 Standard 14.2/4:
When the name of a member template specialization appears after . or -> in a postfix-expression, or after nested-name-specifier in a qualified-id, and the postfix-expression or qualified-id explicitly depends on a template-parameter (14.6.2), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.
Future C++ Standard seems to be still require this keyword according to draft n2857 14.3/4. Some compilers has special mode that allows to compile original code without errors (Comeau compiles it in so called relaxed mode).