I'm trying to compile some Microsoft Visual C++ code using g++. Now I've come across a compiler error which I really can't understand. The (simplified) code looks like this:
template<int X> struct A {
template<class Ret> static Ret call() {
return 0;
}
};
template<int X> struct B : A<X> {
int f() {
return A<X>::call<int>();
}
};
When I try to compile this with g++ (version 4.4.5), I get the following error:
main.cpp: In member function int B<X>::f():
main.cpp:16: error: expected primary-expression before int
main.cpp:16: error: expected ; before int
main.cpp:16: error: expected unqualified-id before > token
If I remove the template type (Ret) from method A::call, the code compiles just fine. Can anybody see whats wrong here?
Thanks!
You need the template keyword:
return A<X>::template call<int>();
call is a dependent name, meaning that its signification depends on a template parameter, which is not known when the compiler process f(). You need to indicate that call is a function template by prefixing it with the template keyword.
The same thing happens when you try to access a nested type: you need to add the typename keyword to indicate that the name denotes a type:
template <typename T>
struct A { typedef int type; };
template <typename T>
void f()
{
typename A<T>::type i = 0; // notice "typename" here
}
And sometimes you even need to mix both:
template <typename T>
struct A
{
template <typename U>
struct inner { };
};
template <typename T>
void f()
{
typename A<T>::template inner<int> var;
}
The use of these two keywords is thoroughly explained in the answers to this question: Where and why do I have to put the “template” and “typename” keywords? (thanks to #Björn Pollex for finding the link).
A is a template, and without knowing X the compiler can't determine the contents of A<X>. Especially it doesn't know that call will end up being a template.
To tell that to the compiler you have to use the template keyword:
template<int X> struct B : A<X> {
int f() {
return A<X>::template call<int>();
}
};
You have to specify that the function you're calling is a template, as it's part of a template class. The compiler is not aware that any given A<X> has a template function named call, and therefore you need to help it.
template<int X> struct B : A<X> {
int f() {
return A<X>::template call<int>();
}
};
Related
I'm setting up a function that initializes tuples based on a tuple type and a functor struct For that has a size_t template argument INDEX to retain the compile-time index. This functor may also depend on other template arguments T.... Because of this the functors exist within other structures (TClass in this example) that hold these template arguments.
The initialization function (called Bar here) has a template<std::size_t> class template argument to ensure that the used class actually can store the index.
While the design I've come up with works fine when I call it from a non-template function, it does not compile if the template T2 of a function does determine the template parameter of the wrapper TClass.
Here is the definition of the functor For wrapped inside TClass:
#include <cstdlib>
template <typename T> struct TClass {
template<std::size_t INDEX> struct For {
void operator()() {}
};
};
And here are the function calls i want to use:
template <template<std::size_t> class FOR> void bar() {
//...
}
template <typename T> void foo() {
bar<TClass<T>::For>(); //Does not compile
}
int main() {
bar<TClass<int>::For>(); //Works
foo<int>();
return 0;
}
The compiler output for the faulty foo-call is:
error: dependent-name ‘TClass<T>::For’ is parsed as a non-type, but instantiation yields a type
Bar<TClass<T>::For>(); //Does not compile
I know that dependent type names usually have to be preceded by a typename but this is also not necessary for the first bar-call. I assumed it was because the template argument can only be interpreted as a type. So I thought that maybe typename would result in correct compilation but if I change foo to
template <typename T> void foo() {
bar<typename TClass<T>::For>(); //Does not compile
}
I get:
error: ‘typename TClass<int>::For’ names ‘template<long unsigned int INDEX> struct TClass<int>::For’, which is not a type
Bar<typename TClass<T>::For>(); //Does not compile
I've also come up with a design where the ()-operator of TClass depends on the template INDEX which also works fine because it is not necessary to use nested types anymore. It looks like this:
#include <cstdlib>
template <typename T> struct TClass {
template<std::size_t INDEX> void operator()() {}
};
template <typename FOR> void bar() {
//...
}
template <typename T> void foo() {
bar<TClass<T>>(); //Does compile
}
Apparently it is not possible to use dependent type names in functions where the template of the type is determined by the function's template parameters, but why? And how do I implement this correctly? To make writing future type checks with type traits easier I would prefer it if I can use a functor.
The compiler cannot know that TClass<T>::For refers to a template at the first stage of template instantiation. It needs a bit of help with template keyword. Fix:
template <typename T> void foo() {
bar<TClass<T>::template For>();
}
The following code does not compile with gcc 6.4 in Debian Sid, due to the error: "typename is not allowed".
struct A
{
template <typename T,typename R> static R f(T x)
{
return (R)x;
}
};
template <class FUNCTION,typename T,typename R> R func()
{
return FUNCTION::f<T,R>(2);
}
int main()
{
return func<A,int,double>();
}
Interestingly enough the following code does compile:
struct A
{
template <typename T> static T f(T x)
{
return x;
}
};
template <class FUNCTION,typename T> T func()
{
return FUNCTION::f(2.f);
}
int main()
{
return func<A,float>();
}
I presume that the second code does compile because the argument of the function provides enough information for GCC to perform template substitution. However I do not understand why the first code fails to compile. So does anybody can explain me why?
You need to use keyword template to tell the compiler that the dependent name f (it depends on the template parameter FUNCTION) is a template name. Only when the compiler knows that's a template name it takes < as the beginning of template-argument-list, otherwise it will try to take < as the less-than operator.
e.g.
return FUNCTION::template f<T,R>(2);
// ~~~~~~~~
The 2nd one works because you didn't use <> (to specify template arguments explicitly).
It appears a forward declaration is causing an issue when specializing some template functions within a template class. I am specializing the class also as it's necessary in order to specialize the function, and this seems to be causing the issue.
Edit: Second question about pre-creating functions for process function:
processor.H
namespace OM{
template<typename MatchT> //fwd decl. ERROR 2. see below.
class Manager;
template<typename MatchT>
class Processor
{
public:
Processor(Manager<MatchT>& mgr_):_manager(mgr_) {}
template<int P>
void process();
void doProcess();
private:
Manager<MatchT>& _manager;
template<int P, int... Ps>
struct table : table<P-1,P-1, Ps... > {};
template<int... Ps>
struct table<0, Ps...>
{
static constexpr void(*tns[])() = {process<Ps>...};
};
static table<5> _table;
};
}
#include "processor.C"
processor.C
namespace OM{
#include "MyManager.H" (includes MyManager/MyConfig)
template<typename MatchT>
template<int P>
inline void Processor<MatchT>::process()
{
...
_manager.send(); //this works..
}
template <> template <>
inline void Processor<MyManager<MyConfig> >::process<1>()
{
_manager.send(); //ERROR 1 - see below.
}
//ERROR here:
template<typename MatchT>
void doProcess()
{
Processor<MatchT>::_table::tns[2](); ERROR 3 below.
}
}
compile errors:
1. error: invalid use of incomplete type 'class Manager <MyManager<MyConfig> >'
2. error: declaration of 'class Manager<MyManager<MyConfig> >'
class Manager;
3. error: no type name '_table' in "class Processor<MyManager<MyConfig> >'
I'm not calling this from a specialized function, so I'm not sure
why I'm getting this.
I can move things around a bit to ensure the _manager calls are not within the specialized functions, but I'd rather not if I don't have to.
I played around with this, I think now I get a similar result.
The problem is the template specialisation and forward declaration together. This should be eqvivalent:
template<typename T> struct A;
template<typename T> class B
{
template<int N>
T f();
};
template<typename T> class B<A<T>>
{
A<T> *a;
template<int N>
T f();
};
template<typename T> struct A{ T i=1; };//works
template<>
template<>
int B<A<int>>::f<1>()
{
return a->i + 1;
}
//template<typename T> struct A { T i = 1; };//error
int main()
{
B<A<int>> b;
}
The compilation for templates comes in two stages:
First, it checks syntax and (some) dependence. So, for example if a in B<A<T>> was not a pointer/reference, but the object itself, it could compile, if that B<A<T>> is constructed after A is defined. (worked for me)
So the second is when the compiler inserts the arguments, here, the compiler must know all objects to generate code.
When fully specialising, as above, the compiler is forced to know all types. It already knows, that f function depends on the implementation of A, so it cannot generate the code.
Therefore you have to define A or Manager before the function specialisation.
I'm experiencing a problem in some code I've been working on. Here is the most simplified version of it I could create:
template <class A>
class Outer {
public:
template <class B>
class Inner {
public:
template <class C>
void foo(Outer<C>::Inner<C> innerC) { }
};
Inner<A> inner;
};
class X {};
class Y {};
int main() {
Outer<X> outerX;
Outer<Y> outerY;
outerX.foo<Y>(outerY.inner);
}
The error is:
error: expected primary-expression before ">" token
and is triggered at compiletime at the declaration of void foo. What is incorrect about my code that is making this happen?
In words, what I am trying to do is have the nested class be able to take in a nested class with any template type - but of course the nested class's template type depends on the outer class's template type, so I use the :: syntax, but that gives an error.
I understand that what I'm trying to do here might not be a good practice, but the purpose of this question is to understand template syntax better.
There is no conversion from 1 to Inner<C>. Is that an error in your reduced test case, or is it supposed to be:
template <class C>
void foo(C innerC) { }
Update: After the code was fixed, it can be seen that the problem is the lack of template before Inner<C>. Otherwise the compiler will assume that Inner is a value.
template <class C>
void foo(Outer<C>::template Inner<C> innerC) { }
just now I had to dig through the website to find out why template class template member function was giving syntax errors:
template<class C> class F00 {
template<typename T> bar();
};
...
Foo<C> f;
f.bar<T>(); // syntax error here
I now realize that template brackets are treated as relational operators. To do what was intended the following bizarre syntax is needed, cf Templates: template function not playing well with class's template member function:
f.template bar<T>();
what other bizarre aspects and gotcha of C++/C++ templates you have encountered that were not something that you would consider to be common knowledge?
I got tripped up the first time I inherited a templated class from another templated class:
template<typename T>
class Base {
int a;
};
template<typename T>
class Derived : public Base<T> {
void func() {
a++; // error! 'a' has not been declared
}
};
The problem is that the compiler doesn't know if Base<T> is going to be the default template or a specialized one. A specialized version may not have int a as a member, so the compiler doesn't assume that it's available. But you can tell the compiler that it's going to be there with the using directive:
template<typename T>
class Derived : public Base<T> {
using Base<T>::a;
void func() {
a++; // OK!
}
};
Alternatively, you can make it explicit that you are using a member of T:
void func {
T::a++; // OK!
}
This one got me upset back then:
#include <vector>
using std::vector;
struct foo {
template<typename U>
void vector();
};
int main() {
foo f;
f.vector<int>(); // ambiguous!
}
The last line in main is ambiguous, because the compiler not only looks up vector within foo, but also as an unqualified name starting from within main. So it finds both std::vector and foo::vector. To fix this, you have to write
f.foo::vector<int>();
GCC does not care about that, and accepts the above code by doing the intuitive thing (calling the member), other compilers do better and warn like comeau:
"ComeauTest.c", line 13: warning: ambiguous class member reference -- function
template "foo::vector" (declared at line 8) used in preference to
class template "std::vector" (declared at line 163 of
"stl_vector.h")
f.vector<int>(); // ambiguous!
The star of questions about templates here on SO: the missing typename!
template <typename T>
class vector
{
public:
typedef T * iterator;
...
};
template <typename T>
void func()
{
vector<T>::iterator it; // this is not correct!
typename vector<T>::iterator it2; // this is correct.
}
The problem here is that vector<T>::iterator is a dependent name: it depends on a template parameter. As a consequence, the compiler does not know that iterator designates a type; we need to tell him with the typename keyword.
The same goes for template inner classes or template member/static functions: they must be disambiguated using the template keyword, as noted in the OP.
template <typename T>
void func()
{
T::staticTemplateFunc<int>(); // ambiguous
T::template staticTemplateFunc<int>(); // ok
T t;
t.memberTemplateFunc<int>(); // ambiguous
t.template memberTemplateFunc<int>(); // ok
}
Out of scope class member function definition:
template <typename T>
class List { // a namespace scope class template
public:
template <typename T2> // a member function template
List (List<T2> const&); // (constructor)
…
};
template <typename T>
template <typename T2>
List<T>::List (List<T2> const& b) // an out-of-class member function
{ // template definition
…
}