Accessing templatized static constexpr member of templatized class with template parameter [duplicate] - c++

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

expected primary-expression before ‘)’ token [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).

Pass class with templated method as template parameter with GCC [duplicate]

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);

Return a struct declared inside template class from a template method [duplicate]

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)

What does the error "expected primary-expression before '>' token" mean in this context? [duplicate]

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>();
//--^^^^^^^^

Compiler error when trying to call template method from private instance [duplicate]

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().