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

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

Related

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

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.

Referencing a template from an inner class [duplicate]

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 2 years ago.
I have the following code
template<typename VP,bool b>
class ValueProcessor{
template<typename Access,typename X> void processValue(X& x){}
};
template<typename VP>
class ValueProcessor<VP,true>{
public:
template<typename Access,typename X> void processValue(X& x);
};
template<typename VP>
template<typename Access,typename X>
void ValueProcessor<VP,true>::processValue(X& x){
class Updater{
ValueProcessor<VP,false> valPro;
X x;
public:
void operator()(){
valPro.processValue<Access,X>(x);
};
};
}
but it fails with this error
source>: In member function 'void ValueProcessor<VP, true>::processValue(X&)::Updater::operator()()':
<source>:23:32: error: expected primary-expression before ',' token
23 | valPro.processValue<Access,X>(x);
|
^
How can I refer to Access from the inner class?
As pointed out in the comment the solution is to add a .template discrimitaor before the member function name:
valPro.template processValue<Access,X>(x);
This is necessary because the type of ValueProcessor<VP,false> valPro is a dependent type (i.e. it's actual type depends on the type of the template parameter VP) the c++ language requires to add the .template disambiguator if you want to call a template member function of VP. Otherwise the parser would interpret the opening < as less-than operator.
See cppreference for a more in-depth discussion. The template disambiguator is described at the very end of that article.

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)

c++ template function error: template-id does not match any template declaration [duplicate]

This question already has answers here:
Templated Functions.. ERROR: template-id does not match any template declaration
(2 answers)
Closed 6 years ago.
I have the following code of function template in C++:
class UserHelpler{
public:
template <typename ValueType>
void createHelper(ValueType& value);
};
template<>
void UserHelpler::createHelper<int>(int* p_user)
{
}
When I build it, it shows the following error:
error: template-id 'createHelper<int>' for 'void UserHelper::createHelper(int*)'
does not match any template declaration
What is the problem and how to fix it?
The problem is that pointers and references are different things. Your template specialization has a signature which is incompatible with the template, as int* and int& are different types.
Probably, you need
createHelper<int>(int& p_user)
instead of
createHelper<int>(int* p_user)
Your template declaration requires your parameter to be of reference type, but in your specialization you provide a pointer instead, which doesn't match. Change your specialization to:
template<>
void UserHelpler::createHelper<int>(int& p_user)
Or alternatively change your template declaration to:
template <typename ValueType>
void createHelper(ValueType* value);

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