Well this has been giving me grief...
#include <iostream>
class InterfaceClass
{
public:
void test()
{
std::cout<<"Hello there.\n";
}
};
template <class T>
class TemplateClass
{
public:
T t;
};
class TestClass: public InterfaceClass
{};
class TestInheritor
{
public:
TemplateClass < InterfaceClass >* templateInherit;
InterfaceClass* normalInherit;
void test()
{
normalInherit->test();
templateInherit->t.test();
}
};
int main (int nargs, char ** arg)
{
TestInheritor ti;
ti.normalInherit = new TestClass; // THIS ONE COMPILES OKAY.
//ti.templateInherit = new TemplateClass <TestClass>; // COMPILE ERROR.
// THIS WORKS THOUGH
TemplateClass <TestClass> * tempClass = new TemplateClass <TestClass>;
ti.templateInherit=(TemplateClass <InterfaceClass>*)tempClass; // WHY DO I HAVE TO EXPLICITLY CAST?
// OUTPUT WORKS AS EXPECTED.
ti.test();
return 0;
}
The normal inheritance example works just fine. The TestClass is automatically converted to a InterfaceClass. However, with the template example, it gives a compile error:
error: cannot convert 'TemplateClass<TestClass>*' to 'TemplateClass<InterfaceClass>*' in assignment
In my mind, it is obvious that you can convert TemplateClass<TestClass>* to TemplateClass<InterfaceClass>*... So what am I missing here?
I can fix it by explicitly casting the template class to the base class, I am able to use the inherited test() function without any problem... So why am I required to explicitly cast the template class?
Sorry if that's confusing... It's hard for me to explain this problem.
Okay, I understand the issue a little more. I have decided to add a template to TestInheritor like so:
template <class T2>
class TestInheritor
{
public:
TemplateClass < T2 >* templateInherit;
InterfaceClass* normalInherit;
void test()
{
normalInherit->test();
templateInherit->t.test();
}
};
int main (int nargs, char ** arg)
{
TestInheritor <TestClass> ti;
ti.normalInherit = new TestClass;
ti.templateInherit = new TemplateClass <TestClass>;
ti.test();
return 0;
}
Probably not the perfect solution, but it works for my purposes.
Ah, and I see your solution:
#include <iostream>
class InterfaceClass
{
public:
void test()
{
std::cout<<"Hello there.\n";
}
};
class TestClass: public InterfaceClass
{};
template <class T>
class TemplateClass
{
public:
T t;
};
template<>
class TemplateClass<TestClass> : public TemplateClass<InterfaceClass>
{
public:
};
class TestInheritor
{
public:
TemplateClass < InterfaceClass >* templateInherit;
InterfaceClass* normalInherit;
void test()
{
normalInherit->test();
templateInherit->t.test();
}
};
int main (int nargs, char ** arg)
{
TestInheritor ti;
ti.normalInherit = new TestClass;
ti.templateInherit = new TemplateClass <TestClass>;
ti.test();
return 0;
}
Consider
class Base
{};
class Derived : public Base
{};
template<typename T>
class TemplateClass
{};
Contrary to what you might think, TemplateClass<Derived> is not a TemplateClass<Base> in the sence of inheritance, so pointers to the former can't be implicitly converted to pointers of the later.
So why does explicitly casting a pointer to TemplateClass<Derived> to a pointer of TemplateClass<Base> compile? Because any pointer of a certain type may be explicitly cast to any pointer of any other type, however there are no guarantees the conversion is valid! You could for instance just as well write
int* i = (int*) new TemplateClass<Derived>;
and it would compile just fine, even though it is clearly an invalid conversion.
Now why does your example work? Sheer luck. At the point a pointer containing an address obtained through an invalid pointer cast gets dereferenced, the program becomes invalid and its bahavior undefined. Anything can happen, including doing what you would expect.
If you want TemplateClass<Derived> to be a TemplateClass<Base> in the sence of inheritance, you can define an specialization of TemplateClass<> stating this relationship explicitly, like the following:
template<>
class TemplateClass<Derived> : public TemplateClass<Base>
{};
Related
Currently, I store pointers of different types in a vector. To archive this, I implemented a class template "Store" which derives from a non-class template "IStore". My vector finally stores pointers to "IStore".
In code:
class IStore
{
public:
IStore() = default;
virtual ~IStore() = default;
virtual void call() = 0;
// ... other virtual methods
};
template<typename T>
class Store : public IStore
{
public:
Store() = default;
virtual ~Store() = default;
virtual void call() override;
// ... other virtual methods
private:
T* m_object = nullptr;
}
And in my main class which holds the vector:
class Main
{
public:
template<typename T>
void registerObject(T* ptr);
template<typename T>
void callObjects();
// ... other methods
private:
std::vector<IStore*> m_storedObjects;
};
So far the current class structure. To describe the problem I need to introduce the following three example structs:
struct A {}
struct B : public A {}
struct C : {}
Other classes should call the Main::registerObject method with pointers to objects of A, B or C types. This method will then create a new Store<A>, Store<B> resp. Store<C> template class object and inserts this objects pointer to m_storedObjects.
Now the tricky part starts: The method Main::callObjects should be called by other classes with a template argument, such as Main::callObjects<B>(). This should iterate though m_storedObjects and call the IStore::call method for each object, which is of type B or which type B is derived from.
For example:
Main::registerObject<A>(obj1);
Main::registerObject<B>(obj2);
Main::registerObject<C>(obj3);
Main::callObjects<B>();
Should call obj1 and obj2 but not obj3, because C isn't B and B isn't derived from C.
My approaches in Main::callObjects were:
1. Perform dynamic_cast and check against nullptr like:
for(auto store : m_storedObjects)
{
Store<T>* base = dynamic_cast<Store<T>*>(store);
if(base)
{
// ...
}
}
which will only work for the same classes, not derived classes, because Store<B> isn't derived from Store<A>.
2. To overwrite the cast operator in IStore and Store, such that I can specify Store should be castable when the template argument is castable. For example in Store:
template<typename C>
operator Store<C>*()
{
if(std::is_convertible<T, C>::value)
{
return this;
}
else
{
return nullptr;
}
}
But this method is never called.
Does anyone have a solution to this problem?
Sorry for the long post, but I thought more code would be better to understand the problem.
Thanks for your help anyway :)
After some thought, I realized that your type erasure, from assigning Store<T> objects to IStore* pointers, makes it impossible to use any compile-time type checking like std::is_base_of and the like. The next best option you have is run-time type information (dynamic_cast<>(), typeid()). As you observed, dynamic_cast<>() can't determine if an object's type is an ancestor of another type, only if an object's type is a descendant of another type known at compile time.
EDIT: With C++17 support, I can think of another way to solve your problem, based on the std::visit example here. If you change your Main interface...
#include <iostream>
#include <vector>
#include <variant>
template <typename T>
class Store {
public:
using value_type = T;
Store(T* object): m_object(object) {}
void call() { std::cout << "Hello from " << typeid(T).name() << '\n'; }
// ... other methods
private:
T* m_object = nullptr;
};
template <typename... Ts>
class Main {
private:
std::vector<std::variant<Store<Ts>...>> m_storedObjects;
public:
// replacement for registerObjects, if you can take all objects in at once
Main(Ts*... args): m_storedObjects({std::variant<Store<Ts>...>(Store<Ts>{args})...}) {}
template <typename U>
void callObjects() {
for (auto& variant : m_storedObjects) {
std::visit([](auto&& arg) {
using T = typename std::decay_t<decltype(arg)>::value_type;
if constexpr (std::is_base_of<T, U>::value) {
arg.call();
}
}, variant);
}
}
};
struct A {};
struct B : public A {};
struct C {};
int main() {
A a;
B b;
C c;
auto m = Main{&a, &b, &c};
m.callObjects<B>();
// > Hello from 1A
// > Hello from 1B
return 0;
}
The following is the simplified code to show my idea.
#include <iostream>
struct base {
virtual int test(){return 0;}
};
struct derived : public base {
virtual int test(){return 1;}
};
template <typename T>
struct foo : public T {
virtual int bar() { return 2;}
};
typedef foo<base> foo_base;
typedef foo<derived> foo_derived;
int main(int argc, char ** argv) {
base * p = new derived(); //It is OK.
std::cout<<p->test()<<std::endl;
foo_base * foo_p = new foo_derived(); //It is not OK
std::cout<<foo_p->bar()<<std::endl;
foo_base * foo_p2 =(foo_base *)(new foo_derived()); //It is working
std::cout<<foo_p2->bar()<<std::endl;
delete foo_p2;
delete foo_p;
delete p;
return 0;
}
I know it is not OK due to the template changing the class inheritance. Is there an elegant way to make the inheritance keep the same after applying the template ?
More specifically, is it possible to build an inheritance between foo<base> and foo<derived>, for example, by using some proxy templates or special pattern like CRTP to rebuild same inheritance after the template instantiation?
As said by Sam Varshavchik in the comments, you cannot automate this process completely since C++ does not have reflection, and thus can't list base classes. However, you've already gone down the route of typedefing your template instantiations, and this is the perfect place to list base classes yourself (hanges highlighted in comments):
struct base {
// Don't forget the virtual destructor for polymorphic destruction
virtual ~base() = default;
virtual int test() const { return 0; }
};
struct derived : base {
int test() const override { return 1; }
};
// U... is the list of thebase classes for T
template <typename T, typename... U>
struct foo : T, foo<U>... {
// ^^^^^^^^^^^ Inheritance is mirrored here
virtual int bar() const { return 2; }
};
// base has no base class
typedef foo<base> foo_base;
// derived has one base class, base.
typedef foo<derived, base> foo_derived;
Live example on Coliru
I have a method in a baseclass that needs the type passed to it for some type-related operations (lookup, size, and some method invocation). Currently it looks like this:
class base
{
template<typename T>
void BindType( T * t ); // do something with the type
};
class derived : public base
{
void foo() { do_some_work BindType( this ); }
};
class derivedOther : public base
{
void bar() { do_different_work... BindType( this ); }
};
However, I wonder if there's a way to get the caller's type without having to pass this so that my callpoint code becomes:
class derived : public base
{
void foo() { BindType(); }
};
Without the explicit this pointer. I know that I could supply the template parameters explicitly as BindType<derived>(), but is there a way to somehow extract the type of the caller in some other way?
There's no magical way to get the caller's type, but you can use CRTP (as a comment mentions) in order to automate this behavior, at the cost of a bit of code complexity:
class base
{
template<typename T>
void BindType(); // do something with the type
};
template <class T>
class crtper : base
{
void BindDerived { BindType<T>(); }
}
class derived : public crtper<derived>
{
void foo() { do_some_work BindDerived(); }
};
class derivedOther : public crtper<derivedOther>
{
void bar() { do_different_work... BindDerived(); }
};
Edit: I should mention, I would kind have expected that foo would be a virtual function, defined without implementation in base. That way you would be able to trigger the action directly from the interface. Although maybe you have that in your real code, but not in your example. In any case, this solution is perfectly compatible with this.
Edit2: After question edit, edited to clarify that solution still applies.
If you want to avoid BindType<derived>(), consider (a bit verbose, I agree) BindType<std::remove_reference<decltype(*this)>::type>(); to avoid passing a parameter. It gets resolved at compile-time and avoids run-time penalties.
class base
{
protected:
template<typename T>
void BindType() { cout << typeid(T).name() << endl; } // do something with the type
};
class derived : public base
{
public:
void foo()
{
BindType<std::remove_reference<decltype(*this)>::type>();
}
};
It will not work as you expect
The result of foo() might be different of what you expect:
class derived : public base // <= YOU ARE IN CLASS DERIVED
{
public:
void foo() { BindType( this ); } // <= SO this IS OF TYPE POINTER TO DERIVED
};
The template paramter is deducted at compile time, so that it will be derived*. If you would call foo() from a class derived_once_more derived from derived, it would still use the type derived*.
Online demo
But you can get rid of the dummy parameter*
You may use decltype(this) to represent the typename of a variable. It's still defined at compile time:
class base
{
public:
template<typename T>
void BindType( )
{
cout << typeid(T*).name()<<endl; // just to show the type
}
virtual ~base() {}; // for typeid() to work
};
class derived : public base
{
public:
void foo() { BindType<decltype(this)>( ); }
};
Online demo
Edit: other alternatives
As template parameters need to be provided at compile-time and not a run time, you can use:
template parameter deduction (your first code snippet)
decltype (see above)
if you intend to add this in all the derived classes you could use a macro to get it done, using one of the above mentionned solution
you could use the CRTP pattern (already explained in another answer).
A possible solution that avoids the intermediate class of the CRTP follows:
class base {
using func_t = void(*)(void *);
template<typename T>
static void proto(void *ptr) {
T *t = static_cast<T*>(ptr);
(void)t;
// do whatever you want...
}
protected:
inline void bindType() {
func(this);
}
public:
template<typename T>
base(T *): func{&proto<T>} {}
private:
func_t func;
};
struct derived1: base {
derived1(): base{this} {}
void foo() {
// ...
bindType();
}
};
struct derived2: base {
derived2(): base{this} {}
void bar() {
// ...
bindType();
}
};
int main() {
derived1 d1;
d1.foo();
derived2 d2;
d2.bar();
}
The basic idea is to exploit the fact that the this pointers in the constructor of the derived classes are of the desired types.
They can be passed as a parameter of the constructor of the base class and used to specialize a function template that do the dirty job behind the hood.
The type of the derived class is actually erased in the base class once the constructor returns. Anyway, the specialization of proto contains that information and it can cast the this pointer of the base class to the right type.
This works fine as long as there are few functions to be specialized.
In this case there is only one function, so it applies to the problem pretty well.
You can add a static_assert to add a constraint on T, as an example:
template<typename T>
base(T *t): func{&proto<T>} {
static_assert(std::is_base_of<base, T>::value, "!");
}
It requires to include the <type_traits> header.
I want to have a container (let's say an std::vector) that would hold various inherited types, and would instantiate them,.i.e. vector of classes --> vector of objects.
For instance:
class A{};
class B: public class A
{};
class C: public class A
{};
void main()
{
std::vector<of inherited A types> typesVec;
std::vector<A*> objectsVec;
typesVec.push_back(class B);
typesVec.push_back(class C);
for (int i = 0; i < typesVec.size(); i++)
{
A* pA = new typesVec.at(i);
objectsVec.push_back(pA);
}
}
Thanks in advance..
This isn't possible in C++ (at least not directly). I can see this happening in a language that has reflection, but C++ doesn't.
What you can do instead is create a factory or simply methods that create objects of the specified type.
Instead of having a vector of types, you'd have a vector of object generators (close enough, right?):
class A{};
class B: public class A
{};
class C: public class A
{};
struct AFactory
{
virtual A* create() { return new A; }
};
struct BFactory : AFactory
{
virtual A* create() { return new B; }
};
struct CFactory : AFactory
{
virtual A* create() { return new C; }
};
//...
typesVec.push_back(new BFactory);
typesVec.push_back(new CFactory);
for (int i = 0; i < typesVec.size(); i++)
{
A* pA = typesVec.at(i)->create();
objectsVec.push_back(pA);
}
There is a reusable approach with templates. This is a generic factory for derived types that comes with an install and a create method which lets you write code like this:
int main() {
TypeVector<Base> t;
t.install<Foo>("Foo");
t.install<Bar>("Bar");
t.create("Foo")->hello();
}
Note it's a sketch implementation. In the real world, you may provide another template parameter to specify the underlying container type (for few types, vector is probably more efficient than set).
The type-vector is this:
template <typename Base>
class Creator;
template <typename Base>
class TypeVector {
public:
template <typename Derived>
void install (std::string const &name) ;
std::shared_ptr<Base> create (std::string const &name) const;
private:
struct Meta {
Meta(std::shared_ptr<Creator<Base>> creator, std::string const &name)
: creator(creator), name(name) {}
std::shared_ptr<Creator<Base>> creator;
std::string name;
};
std::vector<Meta> creators_;
};
We somehow need a way to store the type in an allocatable manner. We do it like boost::shared_ptr, which combines an abstract base class and a template derived class:
template <typename Base>
class Creator {
public:
virtual ~Creator() {}
virtual std::shared_ptr<Base> create() const = 0;
};
template <typename Base, typename Derived>
class ConcreteCreator : public Creator<Base> {
public:
virtual std::shared_ptr<Base> create() const {
return std::shared_ptr<Base>{new Derived()};
}
};
The "concrete creator" is able to allocate an actual object, and return a pointer-to-base of it.
Finally, here are the implementations of TypeVector::install and TypeVector::create:
template <typename Base>
template <typename Derived>
void
TypeVector<Base>::install (std::string const &name)
{
creators_.emplace_back(
std::shared_ptr<Creator<Base>>(new ConcreteCreator<Base, Derived>()),
name);
}
template <typename Base>
std::shared_ptr<Base>
TypeVector<Base>::create (std::string const &name) const
{
for (auto m : creators_) {
if (name == m.name) return m.creator->create();
}
throw std::runtime_error("...");
}
and finally, here's a test:
#include <iostream>
struct Base {
virtual ~Base() {}
virtual void hello() const = 0;
};
struct Foo : Base {
virtual void hello() const { std::cout << "I am a Foo\n"; }
};
struct Bar : Base {
virtual void hello() const { std::cout << "I am a Bar\n"; }
};
int main() {
TypeVector<Base> t;
t.install<Foo>("Foo");
t.install<Bar>("Bar");
t.create("Foo")->hello();
}
You can go further and make any constructor callable for code like ...
...
Bar(Color, Age, int)
...
t.create("Foo", Color::Red, Age::TooOld, 42)
... but this requires an awesome grasp of variadic template argument lists, and how to fold them into a constructor call (can be done and has been done, but it would explode this answer).
Just a quick solution sketch:
The C++ standard does not provide direct calls to constructors. As such you can't have function pointers to constructors; you can, however, have a wrapper function "create", something like:
template<typename T>
T* create () {
return (new T();
}
Provide overloaded create definitions for one argument, two arguments, ... or try to use variadic templates; or, if you already know what types you need, you can create the create functions specifically. Then you can have a function pointer to the create function:
&create<TheType>
Mind that the signature of this function however depends on the type used. You can however create a struct that contains typdefs for the templated type, a typedef for the type pointer, and the create function as a functor operator().
Thus you can have two vectors, one for the function pointers to the create function, or, alternatively to the structs mentioned before, and one with the actual objects. In your case where you only have inherited types, you might be able to define functions A* createB() { return new B(); }, A* createC() { return new C(); }, ... for each inherited type B, C, ... and have a vector for pointers to these create functions and the second vector for the A pointers.
I might point you Andrei Alesandrescu´s book Modern C++ Design (or the Loki library he describes in the book) and the chapter about type lists. This would require you to do the typeVec.insert( type ) at compile time.
I suspect I can't do this directly using a PIMPL pattern. Is it possible to have a smart pointer to a template class? I have not been able to compile by turning knobs on the shared_ptr declaration.
// ============Foo.h ============
// Forward declare the implementation
template <typename T> class FooImpl;
class Foo
{
public:
Foo getInstance(const string& fooType);
...
private:
shared_ptr< FooImpl<T> > m_impl;
};
// ============FooImpl.h ============
template <typename T>
class FooImpl
{
...
};
Under Visual Studio 2008: "error C2065: 'T' : undeclared identifier". I receive a similar error under GCC. If I un-parameterize FooImpl (so that FooTempl inherits from FooImpl), the code will compile.
I suspect I can't paramaterize the smart pointer, but I could be wrong.
EDIT: The second Visual Studio error is more telling: "error C3203: 'FooImpl' : unspecialized class template can't be used as a template argument for template parameter 'T', expected a real type"
Jeff
I'm not entirely certain what you are trying to accomplish, but does this help?
Try 1:
// ============Foo.h ============
// Forward declare the implementation
template <typename T> class FooImpl;
template<class C>
class Foo
{
public:
Foo getInstance(const string& fooType);
...
private:
shared_ptr< FooImpl<C> > m_impl;
};
// ============FooImpl.h ============
template <typename T>
class FooImpl
{
...
};
Try 2:
// ============Foo.h ============
// Forward declare the implementation
class FooImplBase;
class Foo
{
public:
Foo getInstance(const string& fooType);
...
private:
shared_ptr< FooImplBase > m_impl;
};
// ============FooImpl.h ============
class FooImplBase {
public:
virtual void AnAPI();
virtual int AnotherAPI();
};
template <typename T>
class FooImpl : public FooImplBase
{
...
};
The code you have posted cannot compile since T does not mean anything in the context of Foo. The compiler expects a type called T here which does not exist there... Not entirely sure what you are trying to accomplish, but wouldn't the following solve your problem?
// ============Foo.h ============
class FooImplBase {
virtual void WhateverFooImplIsSupposedToDo() = 0;
};
template <typename T> class FooImpl : public FooImplBase {
T mInstance;
public:
FooImpl(T const & pInstance) : mInstance(pInstance) {}
virtual void WhateverFooImplIsSupposedToDo()
{
// implementation which deals with instances of T
}
};
class Foo
{
public:
Foo getInstance(const string& fooType) {
// use m_impl->WhateverFooImplIsSupposedToDo...
}
template < class T >
Foo( T const & pInstance ) : m_impl(new FooImpl<T>(pInstance)) {}
private:
shared_ptr< FooImplBase > m_impl;
};
You're doing it right, just make sure T is defined. This compiles for me on MSVC++ 2010:
#include <memory>
using namespace std;
template<class T>
class Blah {
public:
Blah() { }
};
class Foo {
public:
shared_ptr<Blah<int>> ptr;
Foo() : ptr(new Blah<int>()) { }
};
If you're on an older compiler that hasn't incorporated this feature of C++11 yet, change
shared_ptr<Blah<int>> ptr;
To
shared_ptr<Blah<int> > ptr;
So the compiler doesn't think the >> is a right shift. C++11 doesn't have this problem though.
I don't know in advance I am going to have a Blah, only a Blah.
From the language point of view, Blah<T> is meaningless because T doesn't exist. Depending on what you're exactly trying to do, you can
make Foo a template, too, so that you can declare a template parameter T:
template<typename T>
class Foo
{
public:
Foo getInstance(const string& fooType);
...
private:
shared_ptr< FooImpl<T> > m_impl;
};
which 'fixes' the choice of T when you declare a variable of type Foo<T>;
or make FooImpl explicitly derive from a common base:
class FooBase {
// need to define the interface here
};
// this is a class definition whereas previously you only needed a declaration
template<typename T>
class FooImpl: public FooBase {
// definition here
};
class Foo
{
public:
Foo getInstance(const string& fooType);
// we needed the definition of FooImpl for this member
// in addition this member is quite obviously a template
template<typename T>
void
set(FooImpl<T> const& foo)
{
m_impl.reset(new FooImpl<T>(foo));
}
// not a member template!
void
use()
{
// any use of m_impl will be through the FooBase interface
}
private:
shared_ptr<FooBase> m_impl;
};
where for a given Foo instance any kind of FooImpl<T> can be set dynamically and then used through the FooBase interface. This is a kind of type erasure as it's called in the C++ world.
We can use templates to write a generic smart pointer class. Following C++ code demonstrates the same. We don't need to call delete 'ptr', when the object 'ptr' goes out of scope, destructor for it is automatically.
#include<iostream>
using namespace std;
// A generic smart pointer class
template <class T>
class SmartPtr
{
T *ptr; // Actual pointer
public:
// Constructor
explicit SmartPtr(T *p = NULL) { ptr = p; }
// Destructor
~SmartPtr() {
cout <<"Destructor called" << endl;
delete(ptr);
}
// Overloading dereferncing operator
T & operator * () { return *ptr; }
// Overloding arrow operator so that members of T can be accessed
// like a pointer (useful if T represents a class or struct or
// union type)
T * operator -> () { return ptr; }
};
int main()
{
SmartPtr<int> ptr(new int()); // Here we can create any data type pointer just like 'int'
*ptr = 20;
cout << *ptr;
return 0;
}
out put:
20
Destructor called