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.
Related
Hello template wizards,
I have been concocting a utility template which has one problem left to be solved, but cannot seem to figure it out. The code in this post is a simplification of the code in question, which exhibits the same issue.
Suppose you have a template specialisation as shown below.
enum class Pets { Dog, Cat, Bird };
template <Pets variant>
class Animal;
template <>
class Animal<Pets::Cat> {
void Sound();
};
template <>
class Animal<Pets::Dog> {
void Sound();
};
template <>
class Animal<Pets::Bird> {
void Sound();
};
void Animal<Pets::Cat>::Sound() { printf("Meow!\n"); }
void Animal<Pets::Dog>::Sound() { printf("Woof!\n"); }
void Animal<Pets::Bird>::Sound() { printf("Peep!\n"); }
And then I ruin everything by saying that I might not declare the specialisation of Animal<Pets::Bird>. The latter definition of ::Sound() will fail to compile, as the type doesn't exist. Now, this seems to beg for a SFINAE solution, to me, as we have an unwanted method implementation of a type that we don't want to exist.
I'd like the compiler to simply ignore that last method definition instead of failing compilation, without changing the method signature — that is, I don't want to make the method itself a template.
Do you have any suggestions on how to make this work?
You can’t do this: SFINAE is about overload resolution, and while it also supports the very similar case of selecting a partial specialization, it’s not a general conditional compilation technique. You can use the preprocessor, of course, and you can do tricks like declaring the unwanted function private so that it “doesn’t exist”, but you can’t define a function that just is never mentioned.
I did manage to conjure up a solution, which quite neatly just declares a catch-all, for those types are to be discarded — not quite what I asked for, but closer toward the goal.
This, at least, takes care of the definitions of methods that would otherwise fail compilation.
enum class Pets { Dog, Cat, Bird };
static constexpr Pets kChosenPet = Pets::Cat;
struct AbstractAnimal {
virtual void Sound() = 0;
};
template <Pets variant = kChosenPet, bool B = (variant == kChosenPet)>
struct Animal : public AbstractAnimal {
void Sound();
};
template <Pets variant>
struct Animal<variant, true> : public AbstractAnimal {
void Sound();
};
template <>
void Animal<Pets::Cat>::Sound() {
printf("Meow!\n");
}
template <>
void Animal<Pets::Dog>::Sound() {
printf("Woof!\n");
}
template <>
void Animal<Pets::Bird>::Sound() {
printf("Peep!\n");
}
May be I don't understand something in your question. But what's wrong with just moving declaration of Sound() to Animal?
#include <stdio.h>
#include <type_traits>
enum class Pets { Dog, Cat, Bird };
template <Pets variant>
class Animal {
void Sound();
};
template<>
void Animal<Pets::Cat>::Sound() { printf("Meow!\n"); }
template<>
void Animal<Pets::Dog>::Sound() { printf("Woof!\n"); }
template<>
void Animal<Pets::Bird>::Sound() { printf("Peep!\n"); }
"SFINAE" means "Substitution Failure Is Not An Error". That starts with "Subsitution", an early part of the template instantiation process. And SFINAE is only Not An Error when there are alternatives for the failed template, e.g. other function overloads.
Now in void Animal<Pets::Bird>::Sound(), there is no Substitution, so SFINAE can't apply. We can't introduce it either - the normal way is via std::enable_if, which can turn a non-template declaration into a template declaration that might or might not be instantiated. But that doesn't work - this specialization cannot be a template declaration.
This case can be simplified:
#ifdef FOO
class Foo { int bar; }
#endif
int Foo::bar() { return 1; } // Also not fixable by SFINAE, for the same reason.
I've a class that must depend for some reasons from an int template parameter.
For the same reasons, that parameter cannot be part of the parameter list for the class, instead it is part of the parameter list of its constructor (that is, of course, templated).
Here the problems arose.
Maybe I'm missing something, but I can't see an easy way to provide such a parameter to the constructor, because it cannot be deduced nor explicitly specified.
So far, I've found the following alternatives:
put the above mentioned parameter into the parameter list of the class
create a factory method or a factory function which can be invoked as an example as factory<42>(params)
provide a traits struct to the constructor
I tried to create a (not so) minimal, working example for the last mentioned solution, also in order to explain better the problem.
The class in the example is not a template class for itself, for the key point is the constructor, anyway the real one is a template class.
#include<iostream>
#include<array>
template<int N>
struct traits {
static constexpr int size = N;
};
class C final {
struct B {
virtual ~B() = default;
virtual void foo() = 0;
};
template<int N>
struct D: public B{
void foo() {
using namespace std;
cout << N << endl;
}
std::array<int, N> arr;
};
public:
template<typename T>
explicit C(T) {
b = new D<T::size>{};
}
~C() { delete b; }
void foo() { b->foo(); }
private:
B *b;
};
int main() {
C c{traits<3>{}};
c.foo();
}
To be honest, none of the solutions above mentioned fits well:
moving the parameter into the parameter list of the class breaks completely its design and is not a viable solution
a factory method is something I'd like to avoid, but it could solve the issue
the traits struct seems to be the best solution so far, but somehow I'm not completely satisfied
The question is pretty easy: is there something I missed out there, maybe an easier, more elegant solution, a detail of the language I completely forgot, or are the three approaches mentioned above the ones from which I must choice?
Any suggestion would be appreciated.
You have to pass in something that can be deduced. The simplest thing to use is just a empty wrapper for an int: std::integral_constant. Since you only want ints I believe, we can alias it and then only accept that specific type:
template <int N>
using int_ = std::integral_constant<int, N>;
Where your C constructor just accepts that:
template <int N>
explicit C(int_<N> ) {
b = new D<N>{};
}
C c{int_<3>{}};
You could even go all out and create a user-defined literal for this (a la Boost.Hana) so that you can write:
auto c = 3_c; // does the above
Also, consider simply forwarding the trait through to D. Metaprogramming works better if everything everywhere is a type. That is, still accept the same int_ in C:
template <class T>
explicit C(T ) {
b = new D<T>{};
}
Where now D expects something that has a ::value:
template <class T>
struct D: public B{
static constexpr int N = T::value;
void foo() {
using namespace std;
cout << N << endl;
}
std::array<int, N> arr;
};
It's the same thing either way from the user of C's perspective, but just worth a thought.
I think that solution with "traits" is the best for most cases.
Only to make a little more "mess" in this issue I will provide two more alternatives. Maybe in some very specific cases - they can be in some way better.
Template global variable - you can name it a prototype solution:
class C only differs in its constructor from your original code:
class C final {
// All B and D defined as in OP code
public:
// Here the change - c-tor just accepts D<int>
template <int size>
explicit C(D<size>* b) : b(b) {}
// all the rest as in OP code
};
The prototype - template global variable:
template <int N>
C c{new C::D<N>()};
// this variable should be rather const - but foo() is not const
// and copy semantic is not implemented...
And usage:
int main() {
// you did not implement copy semantic properly - so just reference taken
C& c = ::c<3>;
c.foo();
}
Solution with Base class - and derive class depending on int
This solution, although looks pretty promising I would personally avoid - that only complicates design - and some possibility of object slicing is here present too.
class CBase {
// all here as in OP code for C class
public:
// only difference is this constructor:
template<int size>
explicit CBase(D<size>* b) : b(b) {}
};
Then - the final class:
template <int N>
class C final : private CBase {
public:
C() : CBase(new CBase::D<N>()) {}
using CBase::foo;
};
The usage:
int main() {
C<3> c;
c.foo();
}
Q: One can ask in which way solution with Base class is better than just adding int as another parameter.
A: by base implementation class you do not need to have many "copies" of the same code - you avoid template code bloat...
use template specialization and inheritance:
#include <iostream>
using namespace std;
template <int num> struct A {
A() { cout << "generic" << endl; }
};
template <> struct A<1> {
A() { cout << "implementation of 1" << endl; }
};
template <int num>
struct B : public A<num> {
B() : A<num>() {}
};
int main(int argc, char *argv[])
{
B<1> b;
B<3> b1;
B<4> b2;
}
edit: or you can do it even easier:
template <int num>
struct A {
A();
};
template <int num>
A<num>::A() { cout << "general " << num << endl; }
template <>
A<1>::A() { cout << "specialization for 1" << endl; }
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;
}
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.
I was trying to integrate the boost::share_ptr into a pair of templated classes that were originally derived from a boost::asio example I found. When I define a type within one class which is a shared::ptr of that class. I can't seem to reference the type in another templated class. If I remove templates from the code, it all compiles.
This won't compile:
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
using namespace std;
template <typename TSomething1>
class SomeTemplateT : public boost::enable_shared_from_this<SomeTemplateT<TSomething1> >
{
public:
typedef boost::shared_ptr<SomeTemplateT<TSomething1> > Ptr;
static Ptr Create()
{
return Ptr(new SomeTemplateT<TSomething1>());
}
SomeTemplateT()
{
cout << "SomeTemplateT created" << endl;
}
};
template <typename TSomething>
class OtherTemplateT
{
public:
OtherTemplateT()
{
// COMPILATION ERROR HERE
SomeTemplateT<TSomething>::Ptr someTemplate = SomeTemplateT<TSomething>::Create();
}
private:
};
The code above yields the following compilation error:
src\Templates\main.cpp: In constructor 'OtherTemplateT<TSomething>::OtherTemplateT()':
src\comps\oamp\src\Templates\main.cpp:30: error: expected ';' before 'someTemplate'
Taking virtually the same code without templates compiles without difficulty:
class SomeTemplateT : public boost::enable_shared_from_this<SomeTemplateT>
{
public:
typedef boost::shared_ptr<SomeTemplateT> Ptr;
static Ptr Create()
{
return Ptr(new SomeTemplateT());
}
SomeTemplateT()
{
cout << "SomeTemplateT created" << endl;
}
};
class OtherTemplateT
{
public:
OtherTemplateT()
{
SomeTemplateT::Ptr someTemplate = SomeTemplateT::Create();
}
private:
};
Platform information:
I'm using gcc4.4.0 from MinGW on windows XP (Code:Blocks IDE).
Am I doing something wrong?
EDIT:
I forgot to mention that if I replace the use of the Ptr typedef with the full declaration of the shared ptr:
boost::shared_ptr
Everything compiles fine.
Also, I can use the type in code outside the of the template.
SomeTemplateT<TSomething>::Ptr is a dependent name; that is, its definition depends on the template parameter. The compiler can't assume that it's a type name unless you say so:
typename SomeTemplateT<TSomething>::Ptr someTemplate = SomeTemplateT<TSomething>::Create();
^^^^^^^^
You need to use typename:
typename SomeTemplateT<TSomething>::Ptr someTemplate = SomeTemplateT<TSomething>::Create();
This is required to make parsing possible without semantic analysis. Whether SomeTemplateT<TSomething>::Ptr is a type or a member is not known until SomeTemplateT<TSomething> has been compiled.
A example taken from the C++11 Standard (n3290) that demonstrate why the keyword typename (in this context) is useful.
( 14.6 Name resolution [temp.res] )
struct A
{
struct X { };
int X;
};
struct B
{
struct X { };
};
template<class T> void f(T t)
{
typename T::X x;
}
void foo()
{
A a;
B b;
f(b); // OK: T::X refers to B::X
f(a); // error: T::X refers to the data member A::X not the struct A::X
}