I've encountered a problem(error C2761) while writing specializations for a class. My classes are as follows:
class Print{
public:
typedef class fontA;
typedef class fontB;
typedef class fontC;
typedef class fontD;
template<class T>
void startPrint(void) { return; };
virtual bool isValidDoc(void) = 0;
};
I have a class QuickPrint which inherits the Print class:
class QuickPrint : public Print {
...
};
The error occurs when I try to write specializations for the startPrint method:
template<> // <= C2716 error given here
void QuickPrint::startPrint<fontA>(void)
{
/// implementation
}
template<> // <= C2716 error given here
void QuickPrint::startPrint<fontB>(void)
{
/// implementation
}
The error appears for the remaining specializations as well.
QuickPrint does not have a template member function named startPrint, so specializing QuickPrint::startPrint is an error. If you repeat the template definition in QuickPrint the specializations are okay:
class QuickPrint : public Print {
template<class T>
void startPrint(void) { return; };
};
template<> // <= C2716 error given here
void QuickPrint::startPrint<Print::fontA>(void)
{
/// implementation
}
But if the goal here is to be able to call into QuickPrint polymorphically, you're in trouble, because the template function in Print can't be marked virtual.
try this:
class QuickPrint : public Print {
template<class T>
void startPrint(void) { Print::startPrint<T>(); };
};
Your issue is this line:
template<class T>
void startPrint(void) { return; };
You already provide a function body, but then try to redefine it again (using specialization), which won't work.
Remove that function body and it should work.
To define a default behaviour, provide a default value for template paramter T and then add a single specialization for that one.
Related
I am currently having an issue with templated methods. I have this public class implementing a template method:
namespace Private { class InternalClass; }
namespace Public
{
class PublicClass
{
public:
PublicClass();
virtual ~PublicClass();
template<class T>
bool Add(bool primary);
private:
Private::InternalClass* _pInternal;
};
template<class T>
bool PublicClass::Add(bool primary) { return _pInternal->Add<T>(primary); }
}
The internal class is implemented that way:
namespace Private
{
class InternalClass
{
public:
InternalClass();
virtual ~InternalClass();
template <class T>
bool Add(bool primary);
};
template<class T>
bool InternalClass::Add(bool primary) { return false; }
}
As this internal class header won't be available with the provided sources, I must class forward it within the PublicClass header and I add the include to PrivateClass.h inside the PublicClass.cpp file.
1) Any idea why I would be getting the following error:
error : member access into incomplete type 'Private::InternalClass' / note: forward >declaration of 'Private::InternalClass'
2) What would be the best way of hiding my PublicClass::Add() implementation?
UPDATED
Reason for error at 1) is because of this as stated by Cornstalks.
For 2), how can I hide my implementation without including PrivateClass.h within the PublicClass header file?
You have encountered a very interesting problem - you want to implement the PImpl idiom where the privately implemented class has a template method. Well, this can be solved, meaning you CAN hide the template's implementation, but only when you know which types will be used to instantiate your Add<T> method in your program.
Say, your template will work only with types AClass and BClass. Then you can split your files as follows (comments are inlined):
File public.h:
#ifndef PUBLIC_H
#define PUBLIC_H
// Forward declaration ! It's sufficient in this case !
namespace Private { class InternalClass; }
// Declare all classes your Add<T> method should work with
struct AClass {};
struct BClass {};
namespace Public
{
class PublicClass
{
public:
PublicClass() {}
virtual ~PublicClass() {}
template <typename T>
bool Add(bool primary); // DO NOT implement this method, just declare
private:
Private::InternalClass* _pInternal;
};
// "Explicit instantiation declarations", for each type the method will work with:
extern template bool PublicClass::Add<AClass>(bool primary);
extern template bool PublicClass::Add<BClass>(bool primary);
}
#endif
File public.cpp:
#include "public.h"
// NOTE: this is hidden in CPP file, noone will see your implementation
namespace Private
{
class InternalClass
{
public:
InternalClass() {}
virtual ~InternalClass() {}
template <typename T>
bool Add(bool primary);
};
// Magic! Here is the actual implementation of your private method
template <typename T>
bool InternalClass::Add(bool primary)
{
return false;
}
}
namespace Public
{
// Original definition moved to CPP file !
template <typename T>
bool PublicClass::Add(bool primary)
{
return _pInternal->Add<T>(primary);
}
// And again list the allowed types, this time using "explicit instantiation definitions"
template bool PublicClass::Add<AClass>(bool primary);
template bool PublicClass::Add<BClass>(bool primary);
}
File main.cpp:
#include "public.h"
int main()
{
Public::PublicClass pc;
pc.Add<AClass>(true); // works !
pc.Add<BClass>(false); // works !
// pc.Add<int>(true); linker error as expected,
// becuase there is no explicit instantiation for Add<int>
return 0;
}
I found detect class 's member use global template function is not work:
void printinfo(std::true_type)
{
cout<<"true_type!";
}
void printinfo(std::false_type)
{
cout<<"false_type!";
}
class TestAA
{
public:
void foo();
};
class TestBB;
template<typename T,typename =decltype(&T::foo)>
std::true_type havefoo(T*){return{};}
std::false_type havefoo(...){return{};}
int main()
{
printinfo(havefoo((TestAA*)nullptr));
printinfo(havefoo((TestBB*)nullptr));
}
class TestBB
{
public:
void foo();
};
it fail detect TestBB's foo,is normal? or a complier bug? gcc 4.8.1
The compiler hasn't seen the definition of TestBB at the point of the call to printinfo, only the forward declaration. At that point it doesn't know about any members of TestBB.
After having found answers to many of my questions on stackoverflow, I have now come up against a question of which I can't find the answer and I hope that someone is willing to help me!
My problem is that I want to do an explicit templatization of a function inside a class in C++. My compiler (g++) and a look in the C++ standard (§14.7.3) tells me that this specialization has to be done in the namespace in which the class is declared. I understand that this implies that I cannot put the specialization inside the class, but I don't see the point of this restriction! Does anyone know if there is a good reason for not letting the specializations be made inside the class?
I know that there are workarounds, e.g. to put the function inside a struct, but I want to understand why the language has this design. If there is a good reason for not allowing specialized functions inside the class, I guess I should know it before trying to work around it.
Thanks in advance!
To make my question a little bit more precise: Here is some code from a test example which illustrates what I want to do:
#include <cstdio>
namespace MalinTester {
template <size_t DIMENSIONALITY>
class SpecializationTest {
public:
SpecializationTest() {
privateVariable = 5;
};
virtual ~SpecializationTest() {};
void execute() {
execute<DIMENSIONALITY>();
};
private:
int privateVariable;
template <size_t currentDim>
static void execute() {
printf("This is the general case. Current dim is %d. The private variable is %d.\n", currentDim, privateVariable);
execute<currentDim-1>();
}
template <>
static void execute<0>() {
printf("This is the base case. Current dim is 0.\n");
}
};
This is not possible; g++ says:
SpecializationTest_fcn.h:27: error: explicit specialization in non-namespace scope ‘class MalinTester::SpecializationTest<DIMENSIONALITY>’
SpecializationTest_fcn.h:28: error: template-id ‘execute<0>’ in declaration of primary template
If I put the function execute outside the class, in the name space MalinTester, it will look like this:
#include <cstdio>
namespace MalinTester {
template <size_t DIMENSIONALITY> class SpecializationTest {};
template <size_t currentDim>
void execute() {
printf("This is the general case. Current dim is %d. The private variable is %d.\n", currentDim, privateVariable);
execute<currentDim-1>();
}
template <>
void execute<0>() {
printf("This is the base case. Current dim is 0.\n");
}
template <size_t DIMENSIONALITY>
class SpecializationTest {
public:
SpecializationTest() {};
virtual ~SpecializationTest() {};
void execute() {
MalinTester::execute<DIMENSIONALITY>();
};
private:
int privateVariable = 5;
};
};
};
and I cannot use privatevariable in the templatized versions of execute, as it is private in the class. I really want it private, as I want to have my data encapsulated as far as possible.
Of course I can send privateVariable as an argument to the function, but I think it would be more beautiful to avoid this, and what I really wonder is if there is a good reason for the C++ standard not to allow explicit specialization as in the first code example above.
#Arne Mertz: This is the workaround I have tried, but it doesn't allow using privateVariable either. And most of all, I wonder if it is a good idea to do like this. As I'm not allowed to make specializations of member functions, maybe I shouldn't do specializations of functions encapsulated in structs inside the class either.
#include <cstdio>
namespace MalinTester {
template <size_t DIMENSIONALITY>
class SpecializationTest {
public:
SpecializationTest() {
privateVariable = 5;
};
virtual ~SpecializationTest() {};
void execute() {
Loop<DIMENSIONALITY, 0>::execute();
};
private:
int privateVariable;
template <size_t currentDim, size_t DUMMY>
struct Loop {
static void execute() {
printf("This is the general case. Current dim is %d.\n", currentDim);
Loop<currentDim-1, 0>::execute();
}
};
template <size_t DUMMY>
struct Loop<0, DUMMY> {
static void execute() {
printf("This is the base case. Current dim is 0.\n");
}
};
};
};
Base specialization:
In .h:
template <class T>
class UISelectorSlider : public UISelectorFromRange<T> {
public:
UISelectorSlider();
virtual ~UISelectorSlider();
private:
float width;
float getPositionFromValue(T value);
};
In .cpp under same namespace:
template <>
float UISelectorSlider<MVHue>::getPositionFromValue(MVHue value)
{
return width * (float)value / 360.0;
}
If you want specialized function within specialized class:
Inside class add (.h) (private function):
private:
template <int I>
void foo();
Specialization inside .cpp:
template <>
template <>
void UISelectorSlider<MVHue>::foo<3>()
{
// you can access private fields here
}
UPDATE:
But you cant write something like this:
template <class T>
template <>
void UISelectorSlider<T>::foo<3>()
{
// you can access private fields here
}
You will get: error: enclosing class templates are not explicitly specialized.
It does not matter is this definition inside class or in namespace. The point is that this is not exact partial specialization - this function does not have defined context class (which members you want to call). In other words - when you specialize member you actually try specialize the whole containing class, but not the member itself. And compiler cant do that because class is not yet defined completely. So this is restriction by template design. And if it actually worked - templates would be full equivalent to simple macros.
(And you probably can will solve your task with some macro magic.)
How do I use pimpl for a templated class, when I explicitly instantiate the templates?
All I need is an example code.
What I have tried is:
// MyTemplatedClass.h
template< class T >
class MyTemplatedClass
{
private:
class Impl;
Impl* _pimpl;
public:
void PublicMethod();
}
Here my implementation goes:
// MyTemplatedClass.cpp
template< class T >
class MyTemplatedClass<T>::Impl
{
public:
void PublicMethod();
}
template <class T>
void MyTemplatedClass<T>::Impl::PublicMethod()
{
...
}
Forwarding method call to implementation class:
template< class T >
void MyTemplatedClass<T>::PublicMethod()
{
_pimpl->PublicMethod();
}
Explicit instantiation:
Example with int and double:
template class MyTemplatedClass< int >;
template class MyTemplatedClass< double >;
But it doesn't seem to work.
This would answer your question, but I doubt it does what you hoped to achieve. I suspect you would want to declare the template implementation outside the scope of MyTemplatedClass. It might be a better design to inherit from the template implementation instead of having it as a member variable.
If you compiler does not support extern template declarations I cannot see that having a template pointer to implementation adds any value. You would after all have to have the implementation details you wanted to hide away in the header file anyway.
#include <iostream>
template < class T > class MyTemplatedClass {
private:
template < class U> class Impl {
public:
void ImplPublicMethod() {
std::cout << "Standard implementation" << std::endl;
}
};
Impl<T> * _pimpl;
public:
MyTemplatedClass() : _pimpl(new Impl<T>) { }
~MyTemplatedClass() { delete _pimpl; }
void publicMethod() {
_pimpl->ImplPublicMethod();
}
};
template<> class MyTemplatedClass<int> {
private:
class Impl {
public:
void ImplPublicMethod() {
std::cout << "Integer specialisation" << std::endl;
};
};
Impl * _pimpl;
public:
MyTemplatedClass() : _pimpl(new Impl) { }
~MyTemplatedClass() { delete _pimpl; }
void publicMethod() {
_pimpl->ImplPublicMethod();
}
};
int main(int argc, char ** argv) {
MyTemplatedClass<char> charVersion;
charVersion.publicMethod();
MyTemplatedClass<int> intVersion;
intVersion.publicMethod();
return 0;
}
Methods of a template class always have to be defined in the header. You cannot have a MyTemplatedClass.cpp as compilation unit on its own. What you can do is to #include the file containing the definitions of the methods at the end of MyTemplatedClass.h so that declaration and definition are at least separated at file level. So your problem may be fixed by adding
#include "MyTemplatedClass.cpp"
at the end of MyTemplatedClass.h.
I use pimpls with template classes in my own code, it works for me that way. Your code looks about right - I'd use a std::unique_ptr for pimpl, but I don't see any problems with how you're doing it.
Hi so I have a template class called Body, that takes a single sf::Drawable descendant as a template argument, and i'm trying to overide the Render() function only for the case that the template argument is a sf::Shape.
How do i do this in a non-inline way? The code works when I define the function inside the class, automatically making it inline, but I get link errors (multiple Render symbols detected) when I define the function in a seperate .cpp file.
If it helps here's the code that produces an error:
// in the header file
template<typename drawable= void>
class Body : public sf::Drawable
{
void Render(){Do_Something();
}
template <>
class Body<Shape> : public sf::Drawable
{
void Render();
}
// in the cpp file
void Body<Shape>::Render()
{
Do_Something_Else();
}
You mean like this?
template <typename T>
struct Foo {
int frob() const;
};
// Note: Member function specializations do not require
// full class specializations.
template <typename T>
int Foo<T>::frob() const { return 42; }
template <>
int Foo<float>::frob() const { return 0xbeef; }
#include <iostream>
int main () {
std::cout << Foo<int>().frob() << '\n';
std::cout << Foo<float>().frob() << '\n';
}
Note that the specializations need to be visible where you use them, so in most cases, you have to put them in the header, too.