I'm seeing an error related to templates (compiler is Visual Studio 2012) that I don't understand. Here's the code, boiled down to the essentials:
// Templated class - generic
template <typename T>
class Test
{
public:
void WorksFine() {} // Comiples and works as expected at runtime
void Problem();
};
// Templated class - expicit specialization for T = int.
template <>
class Test<int>
{
public:
void WorksFine() {} // Comiples and works as expected at runtime
void Problem();
};
// The definition below compiles and works fine at runtime.
template<typename T> void Test<T>::Problem() {}
// The definition below gives error C2910.
template<> void Test<int>::Problem() {printf("In Test::Problem(int instantiation)\n");}
For the WorksFine method, the function definition is inside the explicitly specialized class definition, and everything is fine. But for the Problem method, when I define the method outside the explicitly specialized class definition, I get error C2910
Why is this? Error C2910 indicates that the problem is that Test::Problem() is already defined. But it is not defined inside the class...there is no function definition only a declaration.
It seems pretty lame to be able to do something or not depending on where you choose to put the function definition, which I always though was more of a style/syntax decision, not a functionality/semantics decision. Am I missing something?
You don't need the template<>. Just write:
void Test<int>::Problem() {printf("In Test::Problem(int instantiation)\n");}
The template<> syntax on a member specialization is required where explicitly instantiating a member on its own; it is omitted when defining a member of an already existing specialization.
template<typename T> struct X { static int i; };
template<> int X<int>::i = 0; // member instantiation, uses template<>
template<typename T> struct Y { static int i; };
template<> struct Y<int> { static int i; } // template specialization
int Y<int>::i = 0; // no template<>
You don't need template anymore in the explicit function definition: void Test<int>::Problem() {printf("In Test::Problem(int instantiation)\n");}
In this case g++ gives a slightly better error message error: template-id 'Problem<>' for 'void Test<int>::Problem()' does not match any template declaration
Try this:
// The definition below gives error C2910.
void Test<int>::Problem()
{
printf("In Test::Problem(int instantiation)\n");
}
int main()
{
Test<int> hey;
hey.Problem();
return 0;
};
Related
I have a base class with a template member, which is explicitly specialized for some cases. A derived class further specializes the template member of the base class. The rationale beyond that is that the various specialization of the template member do "logically" the same job, adapting to a specific situation. The base class provides some template specializations, which do the task for some cases, a derived class should "extend" the same task to other cases, by further specializing the template member.
Here is a minimal example to illustrate the problems I encounter.
#include <iostream>
struct A {
template <int i>
void dosomething();
void show();
};
template<>
void A::dosomething<0>()
{
std::cout << "0 in A" << std::endl;
}
void A::show()
{
dosomething<0>();
}
struct B : A {
// Without the following declaration:
// error: template-id ‘dosomething<1>’ for ‘void B::dosomething()’
// does not match any template declaration
template <int i>
void dosomething();
};
template<>
void B::dosomething<1>()
{
std::cout << "1 in B" << std::endl;
}
int main()
{
A x;
x.dosomething<0>();
B y;
y.dosomething<0>(); // Link error!
y.show();
y.dosomething<1>();
return 0;
}
The template member A::dosomething() is explicitly specialized for i=0 in the base class. The code for the template is explicitly generated, and called in the member A::show().
The first problem I found are:
A) Without a duplicated declaration
template <int i>
void dosomething();
inside the definition of B, the code does not compile, with the error:
template-id ‘dosomething<1>’ for ‘void B::dosomething()’
does not match any template declaration.
Why is the previous declaration in the base class A not visible?
B) The code above gives rise to a link error:
undefined reference to `void B::dosomething<0>()'
The error is due to the call y.dosomething<0>() in main. It can be avoided by calling instead y.A::dosomething<0>(). Why is dosomething<0>() apparently invisible in an instance of B?
When you do out-of-line definition of a member function the declaration of that function is looked up in the class that is referred before the :: operator.
Consider this:
struct C { void test(); };
struct D : C { };
void D::test() { }; // error, test is not a member of D but of C
this is the same of doing
template<> void B::dosomething<1>()
{ }
dosomething and all it specialization definitions must be qualified by the class it was declared on, i.e in A as the way you did with dosomething<0>.
Also notice that the declaration of dosomething in B is totally unrelated to that of A. you're getting a link error because of the call to a non defined specialization B::dosomething<0>.
You can create the specialization template<> void A::dosomething<1>(){ } but you're not getting the polymorphic behavior that you're expecting, A::dosomething<1> will be shared by all the derived class, if you really need differents versions of dosomething<1> by subclasses, you are confined to the initial repetition, and in order to access A::dosomething<0> from B you do it as static_cast<A&>(b).dosomething<0>().
You also should take a look at static polymorphism in this answer
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.
We all know a C++ class template does not generate member functions that are not used, as illustrated below:
template<typename T>
class A
{
public:
void WrongFunction(T t);
void RightFunction(T t);
};
template<typename T>
void A<T>::WrongFunction(T t)
{
std::vector<T> v;
auto a = "abc" - v;
}
template<typename T>
void A<T>::RightFunction(T t)
{
std::cout << "Success" << std::endl;
}
int main()
{
A<int> a;
a.RightFunction(2);
//a.WrongFunction(1);
return 0;
}
Since the WrongFunction is not called in main, there's no actual code generated for it and therefore no compilation error occurs.
Now, let's introduce an abstract base class that defines the interface for class A(basically, template inheritance):
template<typename T>
class Base
{
public:
virtual void RightFunction(T t) = 0;
virtual void WrongFunction(T t) = 0;
};
template<typename T>
class A : Base<T>
{
public:
void WrongFunction(T t) override;
void RightFunction(T t) override;
};
template<typename T>
void A<T>::WrongFunction(T t)
{
std::vector<T> v;
auto a = "abc" - v;
}
template<typename T>
void A<T>::RightFunction(T t)
{
std::cout << "Success" << std::endl;
}
int main()
{
A<int> a;
a.RightFunction(2);
//a.WrongFunction(1);
return 0;
}
Suddenly, the compiler refuses to work:
prog.cc: In instantiation of 'void A::WrongFunction(T) [with T =
int]': prog.cc:39:1: required from here prog.cc:24:20: error: no
match for 'operator-' (operand types are 'const char [4]' and
'std::vector >')
auto a = "abc" - v;
My understanding of the work flow is, in main, I say create an instance of A. Fine, the compiler then finds the template declaration for A(note that A is not a class; A<SomeType> is.). Wow, it depends on Base<int>. Fine, the compiler then finds the template declaration for Base, plugs int into the position held by T - now we have the declaration for the class Base<int>, but no definition is generated - after all, we did not provide a template for definition generation for Base<SomeType>, and no one has ever created any instance of Base<int> or has called a function on the instance. That's fine. Then the compiler extends the declaration of Base<int> and generates the declaration of A<int>. Wait, on the next line, RightFunction is called. So the compiler finds the template definition for RightFunction for A and plugs in the specific type int and generates the member function definition for A.
Since WrongFunction is never called(no specialization involved either; no explicit instantiation either), the compiler shouldn't even try to generate the code for A<int>::WrongFunction --- my question is, what the heck is going on?
Compiler: gcc 4.9.2
Thanks.
From N3337, §14.7.1/10 [temp.inst]
An implementation shall not implicitly instantiate a function template, a member template, a non-virtual member function, a member class, or a static data member of a class template that does not require instantiation. It is unspecified whether or not an implementation implicitly instantiates a virtual member function of a class template if the virtual member function would not otherwise be instantiated. ...
So it's legal for an implementation to instantiate the virtual member function even though you never call it.
In practice, this is likely to always be the case because when instantiating a class template the compiler also needs to instantiate the vtable for that class which must be filled with the addresses of virtual member functions.
Ok, I am working with g++ 4.8.2 and have the following (somewhat long) code that gets an error message about an incomplete type. I have reduced the code to a smaller chunk for inclusion here and can be compiled directly:
#include <cstdlib>
struct S
{
void method(){}
};
template<size_t sz, size_t tot>
class genpool
{
};
template <class T>
class mempool
{
private:
genpool<sizeof(T), 10*sizeof(T)> p;
};
template <class obj, class mthd>
class functor
{
private:
static mempool<functor<obj, mthd> > pool;
};
template <class obj, class mthd>
mempool<functor<obj, mthd> > functor<obj, mthd>::pool;
int main()
{
typedef void (S::*m)();
typedef functor<S, m> fctr;
fctr f;
}
The compiler error message is:
g++ jj.C
jj.C: In instantiation of ‘class mempool<functor<S, void (S::*)()> >’:
jj.C:30:30: required from ‘class functor<S, void (S::*)()>’
jj.C:37:8: required from here
jj.C:18:17: error: invalid application of ‘sizeof’ to incomplete type ‘functor<S, void (S::*)()>’
genpool<sizeof(T), 10*sizeof(T)> p;
^
Compilation exited abnormally with code 1 at Thu Apr 9 18:50:06
Obviously, the template functor is defined above and all the arguments to functor have been explicitly defined. This seems to imply to me that the sizeof function should be well defined. Is there something that I am missing here?
--Ron
The problem is that the compiler is attempting to instantiate mempool<> before it instantiates functor<>. This is because the compiler feels it needs to be able to define the static member functor<>::pool first before functor<> itself is considered fully defined.
A workaround is to return a mempool<> & from a static member function.
template <class obj, class mthd>
class functor
{
private:
static mempool<functor> & get_pool () {
static mempool<functor> pool;
return pool;
}
};
//template <class obj, class mthd>
//mempool<functor<obj, mthd> > functor<obj, mthd>::pool;
This works because the reference means it is okay for mempool<> to remain incomplete until after functor<> is instantiated. (Actually, a method of a template is not instantiated unless there is code that actually calls it.) When the static method is called, functor<> itself is complete, so the static object within functor<>::get_pool can be properly instantiated.
As a side note, it is acceptable to pass an incomplete type as an argument to a template, but the template has restrictions on what it can actually do with an incomplete type. Everything is fine if the template only requires a reference or pointer to the type for its instantiation.
Your definition of functor is recursive. It requires the compiler to know the size of the type of functor while determining the functor type. You can generate exactly the same problem with this code:
template <class A>
class B {
public:
static const int szA = sizeof(A);
};
template <class A>
class C {
public:
static B<C<A> > b;
};
int main() {
C<int> c;
}
Depending on what your application is, you should be able to do what you want using type traits.
At the time you declare pool inside of functor, you are still defining the functor class, so the type functor is still incomplete.
This is similar to forward declarations:
class functor;
functor func; <<-incomplete here
functor *ptr; <<-pointer is fine
class functor
{
functor func; <<-incomplete again
};
functor func; <<-now complete definition, ok
I don't think you can do it, because you have a recursive definition. For example, you can't do this:
#include <cstdlib>
class B;
class A
{
B b;
};
class B
{
A a;
};
int main()
{
A x;
}
The only way out is to make one of the members a pointer instead of an instance.
I would like to have several different function definitions for a member function in a templated class. Something like this:
template <typename T>
class MyClass
{
void Foo();
T val;
//other functionality and data
};
//handles all types
template <typename T>
void MyClass<T>::Foo()
{
return val;
}
//handles a special type in a different way
template <>
void MyClass<float>::Foo()
{
return val + 5.0f;
}
I've tried implementing this as above and get a linker error for every special type I try to explicitly instantiate. The linker error mentions that the function has already been previously defined. Maybe I'm looking in the wrong places but I couldn't find any resources to help me figure out this problem :(
Q. Is this possible? If so, how do you do this and why does it work?
Thanks!
Here is a workaround that I frequently use. As it as been said before, you have to specialize the complete template. The idea is to make the method you want to specialize a static member of some struct (that should be nested and private for encapsulation reasons). Like this:
template< typename T >
class MyClass {
struct PerformFoo {
static void doFoo () {
std::cout << "Foo for general type" << std::endl;;
}
};
public:
void Foo () {
PerformFoo::doFoo();
}
};
template<>
struct MyClass< float >::PerformFoo {
static void doFoo () {
std::cout << "Foo for float" << std::endl;;
}
};
Now in your main, the code
MyClass< int > myInt;
myInt.Foo();
MyClass< float > myFloat;
myFloat.Foo();
prints
Foo for general type
Foo for float
on your terminal. By the way: this does not involve any performance penalty with modern compilers. Hope this helps you.
By defining the specialized member function as inline function you will get rid of the link error complaining the specialized member function having been defined elsewhere.
//handles a special type in a different way
template <>
inline void
MyClass<float>::Foo()
{
return val + 5.0f;
}
The reason being that a specialized function is no longer a function template, but a concrete function. Therefor it will be compiled several times when compiling source files that includes this header file which is why you get the "already defined" error.
Another solution is to move the implementation of the specialized function out of the header file and put it into the source file, meanwhile, declare the specialized function in the header file. Note that the declaration of the specialized member function must stay outside of the class definition:
/// Declare the specialized function in the header file but outside the
/// class definition.
template <> void MyClass<float>::Foo()
/// Define the specialized function in .cpp file:
template <>
void
MyClass<float>::Foo()
{
return val + 5.0f;
}
I've tried implementing this as above and get a linker error for every special type I try to explicitly instantiate.
What does that mean? If you explicitly specialize the template you cannot explicitly instantiate it anymore for the same template arguments. The whole purpose of an explicit specialization is to prevent the instantiation of it (which is a generated specialization) in favor of your explicit specialization.
So your description does not make sense to me. Just remember that you need to put definitions of templates and member functions of class templates in the header instead of in the .cpp file if you want to instantiate them implicitly. And that explicit specializations need to be declared to everyone who uses their template with their arguments.
// put this specialization into the header, for everyone to see
template <> void MyClass<float>::Foo();
It is not possible. When you specialize a template, you must specialize the entire template, which in this case means the entire class.
You can make foo a template function inside the template class. It is not exactly the same as what you are asking for, but it might meet your needs.
Update:
template<typename T> class Foo {
public:
template<typename R> void foo() {printf("This is foo\n");}
template<> void foo<float>() {printf("This is foo<float>\n");}
};
Or:
template<typename T> class Foo {
public:
template<typename R> void foo() {printf("This is foo\n");}
//template<> void foo<float>() {printf("This is foo<float>\n");}
};
template<> template<> void Foo<float>::foo<float>() {
printf("This is foo<float>\n");
}
along with:
int main(int argc,char * argv[])
{
Foo<int> iFoo;
iFoo.foo<int>();
Foo<float> fFoo;
fFoo.foo<float>();
return 0;
}
generates:
This is foo
This is foo<float>
The syntax for calling foo is a bit awkward.