This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 6 months ago.
So I've got a templatized class which has a templatized static constexpr bool. The setup boils down to this:
#include <type_traits>
template <typename T>
class A {
public:
template <typename U>
static constexpr bool same = std::is_same_v<T, U>;
};
template <typename T>
bool test() {
return A<T>::same<int>; // errors
}
int main() {
A<int>::same<int>; // compiles perfectly
test<int>(); // errors
}
When I access it with actual types like A<int>::same<int>, it compiles just fine, but when I try to access it with a template type, as in the test() function above, it errors. Here is the full list of errors:
constexpr_value.cpp: In function ‘bool test()’:
constexpr_value.cpp:12:21: error: expected primary-expression before ‘int’
12 | return A<T>::same<int>;
| ^~~
constexpr_value.cpp:12:21: error: expected ‘;’ before ‘int’
12 | return A<T>::same<int>;
| ^~~
| ;
constexpr_value.cpp:12:24: error: expected unqualified-id before ‘>’ token
12 | return A<T>::same<int>;
| ^
constexpr_value.cpp: In instantiation of ‘bool test() [with T = int]’:
constexpr_value.cpp:16:12: required from here
constexpr_value.cpp:12:16: error: ‘A<int>::same<U>’ missing template arguments
12 | return A<T>::same<int>;
| ^~~~
The first three errors are from the template itself, and they show up even when I don't use the test() function at all, so it seems like the compiler is assuming A<T>::same<int> is an invalid statement before even checking any specific Ts.
I don't understand these errors at all. Why does A<int>::same<int> compile perfectly, but as soon as you use template types, it doesn't like it at all? I don't even know where to begin fixing this, because the errors tell me nothing. The only difference between compiling and not is using <T> instead of <int>, so is there something I can do with T to tell the compiler that this is a valid statement?
The template code is not equivalent to A<int>::same<int>. This will also compile:
template <typename T>
bool test() {
return A<int>::same<int>;
}
Returning to the erroneous code. The latest GCC 12.1 would produce the hint in the warning:
constexpr_value.cpp: In function 'bool test()':
constexpr_value.cpp:12:16: warning: expected 'template' keyword before dependent template name [-Wmissing-template-keyword]
12 | return A<T>::same<int>; // errors
| ^~~~
As the warning message suggests the fix:
template <typename T>
bool test() {
return A<T>::template same<int>;
}
// ^^^^^^^^
See the hot question Where and why do I have to put the "template" and "typename" keywords? for more info.
Related
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).
This question already has answers here:
C++ template compilation error: expected primary-expression before ‘>’ token [duplicate]
(1 answer)
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 4 years ago.
Is it possible to pass object of a class with templated method as a template parameter under GCC? All search I conducted pointed me to questions regarding templated class, which is not applicable in my case.
Sample code:
#include <iostream>
class Foo
{
public:
template<typename T>
void print(const T& arg) const
{
std::cout << arg << std::endl;
}
};
template<typename A>
void print(const A& printer)
{
printer.print<int>(1);
}
int main()
{
Foo foo;
print<Foo>(foo);
return 0;
}
Compiling under MinGW.org GCC-6.3.0-1 I get the following results:
tmpl.cpp: In function 'void print(const A&)':
tmpl.cpp:16:19: error: expected primary-expression before 'int'
printer.print<int>(1);
^~~
tmpl.cpp:16:19: error: expected ';' before 'int'
VisualStudio compiles the same code cleanly, application works as expected. If I make print function not templated, so that is explicitly takes object of Foo it works as expected both compilers.
You need to use template keyword to tell that print is a template.
Inside a template definition, template can be used to declare that a dependent name is a template.
e.g.
template<typename A>
void print(const A& printer)
{
printer.template print<int>(1);
// ~~~~~~~~
}
print is a dependent name, it depends on the template parameter A. Before the template gets instantiated the compiler knows nothing about A; so you need to add the template keyword to tell the compiler that print is a template, then the < after the name print is valid; otherwise < will be treated as the operator< then cause the error.
You need the template keyword in order to specify that print() is a template, like this:
printer.template print<int>(1);
This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 4 years ago.
I have the following:
#include <vector>
template <class T>
class A
{
public:
struct S
{
int a;
};
std::vector<S> returnStructs(void);
};
template <class T>
std::vector<A<T>::S> A<T>::returnStructs(void)
{
}
int main(void)
{
}
but when I try to compile I get:
error: template argument for template type parameter must be a type; did you forget
'typename'?
std::vector<A<T>::S> A<T>::returnStructs(void)
^
typename
so I switched out that line for:
std::vector<A<int>::S> A<T>::returnStructs(void)
^
'int' instead of 'T'
but then I get a new compiler error:
error: return type of out-of-line definition of 'A::returnStructs' differs from that in the
declaration
std::vector<A<int>::S> A<T>::returnStructs(void)
~~~~~~~~~~~~~~~~~~~~~~ ^
so any thoughts on how to fix this?
Also I realize I can just take struct S out of class A and be done with all these issues but I still feel like it should be possible to solve this without changing class A.
The first compiler error told you exactly what was wrong: did you forget 'typename'
As S is a member of a template you need to add typename to tell the compiler that it should delay the lookup of the name until after the template is resolved:
template <class T>
std::vector<typename A<T>::S> A<T>::returnStructs(void)
This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 6 years ago.
The following code (also on ideone):
// A type templated for different function call signatures.
template <typename Signature> class Used;
template <typename T_Ret, typename ...T_Args>
class Used<T_Ret(T_Args...)> {
public:
// A static method for a specific type.
template <typename T>
static void specific() { }
};
// Some class using the above.
template <typename T>
class User {
public:
// A method that must call the specific function of used.
template <typename T_Ret, typename ...T_Args>
void method() {
using It = Used<T_Ret(T_Args...)>;
using Me = T;
// error: expected primary-expression before '>' token
It::specific<Me>();
}
};
int main() {
User<int> user;
user.method<void, int>();
}
gives the following error (at least using GCC):
test.cpp: In member function 'void User<T>::method()':
test.cpp:20:18: error: expected primary-expression before '>' token
It::specific<Me>();
^
And I have no idea why... The error does not occur if the template parameters are removed from the Used class.
Am I doing something wrong (i.e., missing a template or typename keyword somewhere)? Is this a bug in GCC? Is there a workaround?
Because specific is a dependent name you need a template keyword:
It::template specific<Me>();
//--^^^^^^^^
This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 8 years ago.
(This question is only a duplicate of the other question if you already know the answer!)
(Please note my follow-up question: Why is no template keyword needed if an unrelated global template function with same name exists?)
I get a compiler error at the indicated line when I try to compile templated C++ code with this structure:
template <int N>
struct A {
template <int i>
void f() {};
};
template <int N>
struct B {
A<N> a;
B(A<N>& a) : a(a) {}
void test() {
a.f<1>(); // does not compile
}
};
int main() {
A<2> a;
a.f<1>(); // works fine
B<2> b(a);
b.test();
}
g++ says:
test2.cpp: In member function ‘void B<N>::test()’:
test2.cpp:14: error: expected primary-expression before ‘)’ token
test2.cpp: In member function ‘void B<N>::test() [with int N = 2]’:
test2.cpp:22: instantiated from here
test2.cpp:14: error: invalid operands of types ‘<unresolved overloaded function type>’ and ‘int’ to binary ‘operator<’
clang++ says:
test2.cpp:14:16: error: expected expression
a.f<1>(); // does not compile
^
1 error generated.
The same expression works in the context of main(), but not within the test() method of the templated class B, which has an instance of A as a private variable. I am pretty clueless why this doesn't work.
You have to use a.template f<1>(); inside of b.test().