Specializing a class method based on overall class template - c++

How do I specialize initialize() (see below) where the type isn't based on the method argument, just the overall class template parameter?
template<class STREAM_TYPE>
class MyClass
{
struct MyStruct
{
STREAM_TYPE* _ifs{nullptr};
}
public:
// Use this when STREAM_TYPE = std::ifstream
void initialize()
{
for(MyStruct& ms : _myStructs)
{
ms._ifs = new std::ifstream("");
}
}
// Use this when STREAM_TYPE = std::stringstream
void initialize()
{
}
private:
std::array<MyStruct, 10> _myStructs;
};

Non-template members of class template are themselves independent templates. You can specialize them independently. In your case - by using explicit specialization
// Main template
template<class STREAM_TYPE>
class MyClass
{
void initialize()
{
}
};
// Specialization, declared outside the main template definition
template<>
void MyClass<std::ifstream>::initialize()
{
for(MyStruct& ms : _myStructs)
{
ms._ifs = new std::ifstream("");
}
}
It is up to you to decide which version of the method is the "default" version and which is the "specialized" version. Or maybe you want to declare both versions as specializations.
For example, you might decide to consider both versions as specializations, while defining the main version as deleted
// Main template
template<class STREAM_TYPE>
class MyClass
{
void initialize() = delete;
};
// Specialization, declared outside the main template definition
template<>
void MyClass<std::ifstream>::initialize()
{
for(MyStruct& ms : _myStructs)
{
ms._ifs = new std::ifstream("");
}
}
template<>
void MyClass<std::stringstream>::initialize()
{
}
Just keep in mind that an explicit specialization is no longer a template. It obeys ODR as an ordinary function. Even if your template class is defined in a header file (as template classes usually are), the definition of the above specialization(s) have to go to a .cpp file. The header file should contain mere declarations for your specializations
// header file declarations
template<> void MyClass<std::ifstream>::initialize();
template<> void MyClass<std::stringstream>::initialize();
while the definitions should go to a .cpp file.

What about using SFINAE to enable only the correct version?
template <typename ST = STREAM_TYPE>
std::enable_if_t<std::is_same<ST, std::ifstream>::value> initialize ()
{
std::cout << "ifstream case" << std::endl;
for (MyStruct & ms : _myStructs)
ms._ifs = new std::ifstream("");
}
template <typename ST = STREAM_TYPE>
std::enable_if_t<std::is_same<ST, std::stringstream>::value> initialize ()
{
std::cout << "stringstream case" << std::endl;
}

Related

Declare non-template function in a template class?

NOTE: this post is different from this one: Declare non-template friend function for template class outside the class, so please read my question before marking it as duplicate.
I want to declare a non-template friend function inside a class template, and the arguments and return type of that friend function is unrelated to the template argument. How should I do that?
Please note it is different from that previous question because in that question, arguments and return type of that friend function is related to the template argument.
Example, adapted from that question above:
// class.h
#include <iostream>
using namespace std;
template <typename T>
struct B
{
T value;
int value2;
B() : value2(1) {}
friend void modify(const int&); // unrelated to T!
void printValue2() {
modify(value2);
cout << value2 << endl;
}
};
// define friend function foo() in a class.cpp file, not in the header
void modify(const int &v) { v = v * 2 + 1; } // HOW should I write it?
// main.cpp
int main() {
B<int> b;
b.printValue2();
return 0;
}
I know I can declare modify() outside this template class so it becomes a vanilla, ordinary function. But I want only this template class to have access to modify(). Alternatively, to achieve this goal of access control, I could define modify() to be a static method in this template class, but that would make the method a template method, forcing me to define it in the header.
Followup: if the friend approach above doesn't work, how should I achieve the two goals at the same time:
access control: only that class template can access modify()
be able to define modify() in a *.cpp file, rather in a header.
Accepted Answer:
To achieve the two goals above, don't abuse friendship.
The best practice is let the class template privately inherit a non-template base class, and in that base class declare common non-template methods that are unrelated to template arguments.
Therefore, you are able to define these methods in a separate *.cpp file, reducing the header's size.
You might use private inheritance instead of friendship:
// class.h
#include <iostream>
class B_helper
{
protected:
static void modify(int &v);
};
template <typename T>
struct B : private B_helper
{
T value;
int value2;
B() : value2(1) {}
void printValue2() {
modify(value2);
std::cout << value2 << std::endl;
}
};
// class.cpp
void B_helper::modify(int &v) { v = v * 2 + 1; }
You do it like this:
// class.cpp
void modify(const int &v) { v = v * 2 + 1; }
You are effectively abusing friendship, but ok. What this means is that you need to work around what it means to declare a function with friend: It is only visible through ADL! Now there is no way to refer to modify, because modify doesn't depend on B, so B's scope is never searched for a function named modify.
There is a work-around, but it's not pretty. You need to declare modify in every function where you use it. You could also declare it in global scope, but then everyone can call it. Alternatively, you can always declare it in a detail namespace (but this has the same issue a bit):
template<typename T>
void B<T>::printValue2() {
void modify(const int&);
modify(value2);
cout << value2 << endl;
}
As I said in the comments, friendship controls access to a class. As long as your function modify() is a standalone function, it cannot be befriended. As you want to call it from a template, it cannot be hidden it in a .cpp file either, but must be visible with the definition of the class template B and its member using modify().
One solution is to put modify as a static method in a auxiliary non-template class, which in turn befriends the template B<>.
// file foo.h (header)
namespace foo {
template<typename> class B; // forward declaration
class exclusive_for_B
{
template<typename T>
friend class B<T>;
static void modify(int&x) // must take int&, not const int&
{ x &= x+42; }
};
template<typename T>
class B
{
int val;
public:
...
void printvalue()
{
exclusive_for_B::modify(val); // access via friendship
std::cout << val << '\n';
}
};
}

Using pimpl with Templated Class and explicitly instantiated templates

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.

How to define a template overide's function in a non-inline way

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.

checking class in c++ templates without class instance

I need to write template which generates some code depending on whether template parameter is instance of of some class. The template can be generated for all classes but only in case the class is subclass of other class the code should be executed.
The problem is that function that should be implemented does not receive any instance of the class, so the only thing known is class name. So it is impossible to achieve this with dynamic_cast as it demands instance of the object
template<T>
class A
{
void somefunction(void)
{
if (T instanceof Foo) then ...
else ...
}
}
adding some explanation
class X: public Foo {};
class Y {};
class A<X> {} // special logic is generated
class A<Y> {} // special logic is NOT generated
You can use template specialization or boost::is_base_of from the boost traits library
Or of course write your own traits, but shouldn't, for you have not mastered templates yet.
Using specialization, you could
template<T>
class A
{
void somefunction() {
// generic version
}
};
template<>
class A <Foo>
{
void somefunction() {
// foo version
}
};
As always, let me recommend Vandevoorde/Josuttis "C++ Templates: The Complete Guide".
If you fear code bloat because only one memberfunction out of many needs to be specialized, you can still outsource that function:
template <typename T> struct somefunction_helper {
static void thatfunction () {
// generic form
}
};
template <> struct somefunction_helper<Foo> {
static void thatfunction () {
// Foo form
}
};
template<T>
class A
{
void somefunction() {
somefunction_helper<T>::thatfunction();
}
};
This is what template specializations are for. They're more difficult to write, but that's what you do with them. For example:
template<T> class A
{
void somefunction(void) {
...//default for any object type.
}
};
template<> class A<Foo>
{
void somefunction(void) {
...//specific to the type Foo.
}
};
Yes, it requires an extra bit of work. There are some template metaprogramming ways to do this the way you want, but someone else will have to explain those.
Either specialize A or delegate the work of the someFunction() member function template to some free function template which you can (fully) specializes on T.
Since specialization won't work since the template parameter will only ever be derived from Foo, use what another answer said: is_base_of, either from Boost or from the standard library if it already supports parts of C++0x:
#include <type_traits> // C++0x
class Foo{};
template<class T>
class A{
void specialOnFoo(){
// dispatch the call
specialOnFoo(std::is_base_of<T, Foo>::type());
}
void specialOnFoo(std::true_type){
// handle Foo case
}
void specialOnFoo(std::false_type){
// non-Foo case
}
};
Edit #2 - see working example. Please note that this the run-time equivalent of template specialization (which happens at compile-time) and requires RTTI enabled.
#include <iostream>
#include <typeinfo>
using namespace std;
class Foo {};
class X: public Foo {};
class Y {};
template<typename T> class A {
public:
void somefunction()
{
if (typeid(T) == typeid(X)) {
cout << "X specific logic happening" << endl;
}
else {
cout << "Default behavior" << endl;
}
}
};
int main() {
A<X> ax;
A<Y> ay;
ax.somefunction(); // prints "X specific logic happening"
ay.somefunction(); // prints "Default behavior"
}
typeid can be used with templates to extract the type of the template parameter -- as described below:
// expre_typeid_Operator_3.cpp
// compile with: /c
#include <typeinfo>
template < typename T >
T max( T arg1, T arg2 ) {
cout << typeid( T ).name() << "s compared." << endl;
return ( arg1 > arg2 ? arg1 : arg2 );
}
Taken from: http://msdn.microsoft.com/en-us/library/fyf39xec(v=vs.80).aspx
Note that the value of name() is implementation defined.

C++ class declarations and namespaces

I'm having an issue with a C++ library I'm trying to write. It's the usual setup, one cpp file, one header file. I want the header file to only expose the parts that are meant to be used (I have an abstract base class for instance, I don't want in the header file). So far, I'm just working with a single file (I assume this should make no difference, as includes are done by the preprocessor, which doesn't care about anything).
You'll note that the "header file" is spread over two spots, before and after the header implementation file.
#include <stdio.h>
// lib.h
namespace foo {
template <class T> class A;
}
// lib.cpp
namespace foo {
template <class T> class A {
private:
T i;
public:
A(T i) {
this->i = i;
}
T returnT() {
return i;
}
};
};
// lib.h
namespace foo {
template <class T> T A<T>::returnT();
}
// foo.cpp
void main() {
foo::A<int> a = foo::A<int>(42);
printf("a = %d",a.returnT());
}
So, naturally, I'd like my header file to contain just
namespace foo {
template <class T> class A;
template <class T> T A<T>::returnT();
}
But my compiler does not like this (it complains that returnT is not a member of foo::A<T>. The reason I don't want to put the class declaration itself in the header is that then it would (as I understand it), contain all the private and similar stuff, which I'd like to hide.
Maybe it's just me, but the following header file seems "bad", at least as an "interface specification." It exposes some of the internals of A, which a user of the lib would not need to know about.
// lib.h
namespace foo {
template <class T> class A {
private:
int i;
public:
A(T);
T returnT();
};
}
// lib.cpp
namespace foo {
template <class T> A<T>::A(T i) {
this->i = i;
}
template <class T> T A<T>::returnT() {
return i;
}
};
Is this the accepted way of doing it? I'd like a more abstract header file, if at all possible.
You cannot separate the definition of a template from its declaration. They both have to go into the header file together.
For "why?" I recommend reading "Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file?".
I may have misread your question. To address what may also be your question, this is not valid:
namespace foo {
template <class T> class A;
template <class T> T A<T>::returnT();
}
It is not valid for the same reason that this is not valid:
namespace foo {
class A;
int A::returnT();
}
Member functions must be declared inside the definition of the class.
There are two problems with .cpp files you are dealing here:
I.
If you want to put an instance of that class on the stack (like you do in your main()) the compiler needs to know the size of the class (to allocate enough memory). For that it needs to know the members and by that the complete declaration.
The only way to hide the class' layout away is to built up an interface and a factory method/function and put the instance on the heap in the factory.
As an example (without the template; see below to know why):
namespace foo {
class IA {
public:
virtual ~IA();
virtual int returnT() = 0;
static IA *Create();
};
}
In your .cpp you then do:
namespace foo {
class A : public IA {
private:
int i;
public:
A() :
i(0) {
}
virtual ~A() {
}
virtual int returnT() {
return i;
}
};
IA::~IA() {
}
IA *IA::Create() {
return new A();
}
}
BTW: Using smart pointers would be suggested...
II.
Since you are using a template the method definitions must be either visible via header file or explicitly instantiated for a specific set of types.
So you can split up your code into a lib.h and a lib_impl.h:
lib.h:
namespace foo {
template <typename T> class IA {
public:
virtual ~IA() {
}
virtual T returnT() = 0;
static IA *Create();
};
}
lib_impl.h:
namespace foo {
template <typename T> class A : public IA<T> {
private:
T i;
public:
A() :
i(T()) {
}
virtual ~A() {
}
virtual T returnT() {
return i;
}
};
template <typename T> IA<T> *IA<T>::Create() {
return new A<T>();
}
}
so you include the lib_impl.h where ever you need the impleemntations.
To use the explicit instantiations add a lib.cpp and just let that file allow to include lib_impl.h:
lib.cpp:
#include <lib_impl.h>
namespace foo {
template class IA<int>;
template class A<int>;
template class IA<float>;
template class A<float>;
template class IA<char>;
template class A<char>;
// ...
}