Check for template class equality through base class pointer - c++

Is it possible to check, through a base class pointer, whether different derived template classes are specialization of the same template class?
This is achievable through introducing an intermediate non-template base-class. However, i would like to know whether this pattern is avoidable when the sole purpose of this intermediate class is for identification:
class A{}
class B_base : public A{}
template<T>
class B : public B_base {}
// There may be other derived classes of A
template<T>
class C: public A{}
void main() {
// ... some vector of pointers to A derived objects
std::vector<A*> v;
for(auto& i : v){
// Check whether i is any specialization of B through a
// dynamic_cast to the intermediate class
if(dynamic_cast<B_base*>()){
// This is a B_base object,
}
}
}
Ideally, i would like something like this, to avoid the intermediate class.
class A{}
template<T>
class B : public A{}
// There may be other derived classes of A
template<T>
class C: public A{}
void main() {
// ... some vector of pointers to A derived objects
std::vector<A*> v;
for(auto& i : v){
// Check whether i is any specialization of B
if(templateTypeId(i) == templateTypeId(B*)){
// This is a B object with some unknown specialization
}
}
}

Different specializations of a template are entirely unrelated types for most purposes. Template argument deduction can deduce a template and its arguments from such a type, but that happens entirely at compile time. There is no guaranteed run time information that can tell whether a class is a specialization of a given template, whether two classes are specializations of the same template, etc.
So you would need to set up a way to test this yourself, but your intermediate class method is not the only option. The most straightforward way would be to put a way to test it into the base A class:
class A {
public:
virtual ~A() = default;
virtual bool is_B() const noexcept { return false; }
};
template <class T>
class B : public A {
public:
bool is_B() const noexcept override { return true; }
};
Though this gets a bit ugly if there are several different B-like categories to test for, and doesn't work if it should be possible to extend A with new subtypes, and then test for those subtypes in a similar way.
Another idea would be to associate the type check with an object address:
struct type_tag {
constexpr type_tag() = default;
type_tag(const type_tag&) = delete;
type_tag& operator=(const type_tag&) = delete;
};
class A {
public:
virtual ~A() = default;
virtual bool matches_type(const type_tag&) const
{ return false; }
};
inline constexpr type_tag B_tag{};
template <class T>
class B {
public:
bool matches_type(const type_tag& tag) const override
{ return &tag == &B_tag; }
};
This pattern also allows for categories of subtypes that don't come from just one template. It also doesn't prevent a new class from "lying" about its own type, if that might be a concern, but it might be best not to try to prevent that, but let any implemented derived class be responsible for its own behavior, which might mean it wants to act "almost exactly like" some other type.

May be a better design is to add required virtual functions to interface A, so that you can invoke them directly on A* without guessing the derived class. The latter is an anti-pattern because it defeats the purpose of polymorphism: the idea that a piece of code can work with object of different classes without knowing their exact type. You may as well put objects of different types into different containers and not use ploymorphism based on virtual functions at all.

Related

I wonder if I can allocate a class to a particular member data and create an instance of that class

I want to know whether it is possible or not.
I have a class in one project.
class A { ...
void CreateInternal(void);
B* m_pData;
... }
void A::CreateInternal(void)
{
m_pData= new B;
}
and in other project, i add C class and want to make it in A::CreateInernal(void) like this...
void A::CreateInternal(void)
{
m_pData = new C; // ex) B is base class of C
}
Of course, i can make Class A to template class, however, i do not want it. I want to use it last. ( Suppose that dependency or other build error is free )
typename<class T>
class A { ...
void CreateInternal(void);
T* m_pData
... }
void A<T>::CreateInternal(void)
{
m_pData = new T;
}
I just want to register Class B or Class C in Class A.
Is it possible??
Thank you for your reply!
As denoted in the comments:
You don't want to make A a template class.
You the classes you want to create instances of share a common base class, which is the type of the member pointer as well (precondition for the following!).
So you can make createInternal a template function instead:
template <typename T>
void A::createInternal()
// ^^^ A still is a normal class!
{
m_data = new T();
// (will fail if T is a different type NOT inheriting
// from the base class in question)
}
Side note: Normally, if template functions are provided inside classes, you would have to implement them in the header file (typically at least, there are ways around...), if createInstance is private, though, and you don't call it from public inline functions, you can safely implement it in the source file as well as this file will be the only location the template ever is used.
You can even go a step further and allow to call all possible constructors by use of a variadic template:
template <typename T, typename ... TT>
void A::createInternal(TT&& ... tt)
{
m_data = new T(std::forward(tt)...);
// (will fail, if there is no matching constructor
// for the arguments provided)
}
OK, you now have to specify which instance you want to create:
void A::f()
{
createInternal<B>();
createInternal<C>();
}
I assume this being acceptable as you need to be able to tell somehow which type you actually want to create.
The alternative would be different functions for different classes (createInternalB, createInternalC), but that certainly is less elegant.
Side note:
Is it possible??
Even if your classes did not share a common base class, you still could store your objects created in a std::variant or, if you happen to compile pre-C++11, even in a union (but you need to take care yourself about which type actually is stored – in this respect, std::variant is just much safer, so prefer it whenever possible).
Update on new comments:
If you want to be able to create arbitrary objects within A without having to know which one actually is created, now offering two further alternatives:
In first variant you could make createInternal virtual in A (possibly even pure virtual) and then override in derived classes to provide the objects suiting your needs.
In second variant you provide an instance of some object provider class; assuming D is the base class of both B : public D and A : public D, so then the solution might look similar to this:
class A
{
public:
class ObjectProvider
{
public:
virtual ~ObjectProvider() = default;
public: virtual D* createInstance() = 0;
};
template <typename T>
class TheObjectProvider : public ObjectProvider
{
public:
D* createInstance() override
{
return new T();
}
};
A(std::unique_ptr<ObjectProvider> p)
: objectProvider(std::move(p))
{ }
private:
std::unique_ptr<ObjectProvider> objectProvider;
std::unique_ptr<D> m_data;
void createInternal()
{
m_data = objectProvider->createInstance();
}
};
Usage:
A ab(std::make_unique<A::ObjectProvider<B>());
// your own custom object provider:
class OP : public A::ObjectProvider
{
public:
C* createInstance() override { return new C(); }
};
A ac(std::make_unique<OP>());
The std::unique_ptr as parameter (although in general, it is not recommended to use smart pointers for) now has an important function: It indicates that the class will take ownership of the object passed, i. e. is a sink in Herb Sutter's wording – see his GotW91).
If you have a most commonly used data type (e. g. B), you could provide an overloaded default constructor providing an object provider for this type (or possibly the base type D, if not being abstract).

Abstract base class using template argument from derived class

I have a base class which provides pure virtual interfaces. I need this to store pointers to derived-class objects in a list of pointers to the base class.
The derived class is created using the template mechanism. The problem is now that if I want to have a virtual interface to return a type which is known only to the derived class, I need to pass it as a template argument as well. This is where the dilemma starts...
template <typename ITEM>
class base {
public:
virtual ITEM* get() = 0;
};
template <typename ITEM>
class derived : public base<ITEM>{
public:
ITEM* get() {...};
};
But when using a template in base I need to know this even when creating a list of base pointers:
base* myList[10] = {derived1, derived2,...}
Of course I don't know that type when I define my list. So I need to get rid of the template in my base class somehow.
EDIT: Got rid of this approach because it wasn't a useful approach at all. So no solution for this issue.
The code you write is not valid; there is not a single base type that is then parameterised like in Java, but a number of base<T> types. There is a way to obtain a wrapper for a truly generic object, and it is called "type erasure". It is used, for example in the implementation of boost::any.
Basically, you have a non-template base class with virtual functions, and then you make a template derived class that implements them. Note that the simplified version shown here does not work if you want to have an array of base objects, because base has pure virtual functions and thus cannot be instantiated (and because the T member of the derived type would be sliced off).
struct base;
template<typename T>
struct derived;
struct base {
virtual ~base();
// In this class we don't know about T, so we cannot use it
// Other operations that delegate to the derived class are possible, though
virtual std::size_t sizeofT() const = 0;
virtual const std::type_info& typeofT() const = 0;
// Since all you want is a pointer in "get", you could write it as a void*
virtual void* getPtr() = 0;
// Otherwise, we can implement this template function here that calls the virtual.
// Note that function templates cannot be virtual!
template<typename U>
U& getAs() {
// Verify that the type is the _same_ (no up/downcasts allowed)
// std::bad_cast is thrown here if U is not the same T used to build this object
derived<U>& meAsU = dynamic_cast<derived<U>&>(*this);
return meAsU.obj;
}
};
template<typename T>
struct derived : public base {
T obj;
// A couple of ctors to initialize the object, and the default copy/move ctors/op=
virtual ~derived();
derived(const T& o) : obj(o) {}
derived(T&& o) : obj(std::move(o)) {}
std::size_t sizeofT() const override {
return sizeof(T);
}
const std::type_info& typeofT() const override {
return typeid(T);
}
void* getPtr() override {
return static_cast<void*>(&obj);
}
};
If you want to use the base type directly as a variable, or in an array or container (vector, list, etc.), you need dynamic allocation - there are no two ways around it. You have two choices, which differ on where to place the responsibility for the dynamic allocation:
You can use the solution above if you limit yourself to having arrays of pointers to base. E.g. an array of std::unique_ptr<base>. The pointed-to objects would be of type derived<something>.
base err1; // Error, abstract class (what would it contain?)
base err2 = derived<int>(2); // Still abstract class, and the int would be sliced off
std::unique_ptr<base> ok(new derived<int>(3)); // Works
std::vector<std::unique_ptr<base>> objects;
objects.push_back(std::make_unique(new derived<int>(5)));
objects.push_back(std::make_unique(new derived<std::string>(2)));
int& a = objects[0].getAs<int>(); // works
std::string& b = objects[1].getAs<std::string>(); // works too
std::string& bad = objects[1].getAs<double>(); // exception thrown
Otherwise, you would have to implement the dynamic allocation in the base/derived classes themselves. This is what classes like boost::any or std::function do. The simplest any object would simply be a wrapper of an unique-ptr of the base class I showed here, with appropriate implementations of operators, etc. Then, you can have a variable of type any x = y; and the class would, inside its constructor, do the required new derived<Y>(y) required.

How to force use of curiously recurring template pattern in C++

I have the following base template class.
template<typename T>
class Base {
public:
void do_something() {
}
};
It is intended to be used as a curiously recurring template pattern. It should be inherited like class B : public Base<B>. It must not be inherited like class B : public Base<SomeoneElse>. I want to statically enforce this requirement. If someone uses this wrong, I expect an error in the compiling phase.
What I'm doing is putting a static_cast<T const&>(*this) in do_something(). This way the class inheriting the template is or inherits from the class provided as the template parameter. Sorry for the confusing expression. In plain English, it requires B is or inherits from SomeoneElse in class B : public Base<SomeoneElse>.
I don't know if it's the optimal way to achieve this. Looks gross to me.
However I want to do more. I want to ensure B is SomeoneElse itself. How can I do that?
Make the constructor (or destructor) of Base private, and then make T a friend. This way the only thing that can construct/destruct a Base<T> is a T.
If your class contains some code that says:
T* pT = 0;
Base *pB = pT;
Then there will be a compiler error if T is not assignment-compatible with Base.
This kind of check is formalised in C++11 so you don't have to write it by hand and can get helpful error messages:
#include <type_traits>
template<typename T>
class Base {
public:
void do_something()
{
static_assert(
std::is_base_of<Base, T>::value,
"T must be derived from Base");
}
};
class B : public Base<B> { };
int main()
{
B b;
b.do_something();
}
As to ensuring that Base's type parameter is exactly the class that is deriving from it, that seems conceptually flawed. A class that is acting as a base class can't "talk about" the type that is inheriting it. It may be inherited more than once via multiple inheritance, or not at all.
Two good answers so far. Here is another which uses the idiom of generating custom access keys to certain methods (in this case a constructor). It provides an absolute guarantee of correct use while not exposing private methods in the base to the derived.
It can also be used to control access to other methods in the base class on a case-by-case basis.
template<class Derived>
struct Base
{
private:
// make constructor private
Base() = default;
protected:
// This key is protected - so visible only to derived classes
class creation_key{
// declare as friend to the derived class
friend Derived;
// make constructor private - only the Derived may create a key
creation_key() = default;
};
// allow derived class to construct me with a key
Base(creation_key)
{}
// other methods available to the derived class go here
private:
// the rest of this class is private, even to the derived class
// (good encapsulation)
};
struct D1 : Base<D1>
{
// provide the key
D1()
: Base<D1>(creation_key())
{}
};

Casting specialized base pointer to derived pointer that specializes on additional template parameter ("adding on" a specialization)

I'd like to cast a base class pointer to a derived one in order to take advantage of some methods unique to the derived class. Here's an Ideone of a simple example that works:
template<typename A>
class Base {};
template<typename A, typename B>
class Derived : public Base<A> {
public:
void doSomething() {}
};
int main() {
Base<int>* foo = new Derived<int, double>;
static_cast<Derived<int, double>*>(foo)->doSomething();
return 0;
}
Now, the problem is that my foo is actually a member of a templated class,
template<typename A>
class Container
{
public:
Base<A>* foo;
};
and at the time I cast, I don't know what A is:
int main() {
Container<int> container;
container.foo = new Derived<int, double>;
// a lot of code later...
static_cast<Derived< /* ??? */ , double>*>(container.foo)->doSomething();
return 0;
}
Then I thought this might be possible if I could somehow store what A is in my base class, like
template<typename A>
class Base
{
public:
static type template_type = A; // made-up syntax
};
so that I can refer to it like
static_cast<Derived<container.template_type, double>*>(container.foo)->doSomething();
but according to this question it's not possible to store types in C++.
How do I achieve this cast without knowing A?
That is, how do I cast a specialized base pointer to a derived pointer that specializes on an additional template parameter? In less technical terms, I just want to take a Base pointer and tack on the other specialization necessary to form the Derived pointer.
Usually it is not wise to do an up-cast and there is usually a better design that you may use to avoid the need of up-cast at all, but if you really need it, then you may use dynamic_cast to do this.
this operator try to convert from one type to another type dynamically and if conversion is not possible, it will return nullptr. But remember that it only work for polymorphic types(types that have at least one virtual function) so in this case your Base class must be polymorphic(since you are holding a pointer to base class, you possibly need a virtual destructor to allow delete to work on base pointer and this make Base a polymorphic class).
But to remember a type in C++, you have 2 options:
Use typedef:
You may use typedef to hold type information in the class:
template< class A >
class my_class
{
public:
typedef A input_type;
};
template< class T >
void do_something(T const& t)
{
typename T::input_type n;
do_something_on_input_type(n); // possibly overloaded for different input types
}
this approach is really fast and have no overhead in runtime, but you can use it only in cases when you want to do something in compile time. and if the type of pointer is not determined until runtime this approach is not useful.
Use std::type_info
Using this you can actually hold type information with the class:
class Base { virtual std::type_info const& get_type() const = 0; };
class Child : public Base
{
virtual std::type_info const& get_type() const { return typeid(Child);
void child_specific_function() { /**/ }
}
class ChildOfChild : public Child
{
virtual std::type_info const& get_type() const { return typeid(ChildOfChild); }
// ...
};
void do_something(Base* base)
{
if (base->get_type() == typeid(Child))
{
static_cast<Child*>(base)->child_specific_function();
}
}
This sound really interesting but, it is only useful when you know exact type of the object and it does not work for derived types, so this approach work for Child but not for ChildOfChild

C++: Design, Function template overriding and lack of polymorphism

Have a base class A, and a derived class B which overrides function template Func:
class A
{
A() {...};
~A() {};
template <class T>
void Func(const String &sInput, T &tResult)
{...}
};
class B : public A
{
B() {...}
~B() {};
template <class T>
void Func(const String &sInput, T &tResult)
{...}
};
(Note that Func is non-virtual, given the lack of support in C++ for templated virtual functions.)
Now have a mainprog API, class M:
class M
{
M(boost::shared_ptr<A> &pInterfaceInput): pInterface(pInterfaceInput)
{}
template <class T>
Evaluate(const String &sInput, T &tResult)
{
pInterface->Func<T>(sInput, tResult);
}
private:
const boost::shared_ptr<A> pInterface;
};
I want the function Evaluate here to support calls to functions on base class A or any of its derived classes (such as B). This class was written with polymorphism in mind before I re-designed class A and B to have templated functions.
Now the problem here is that if I pass a shared pointer of the base type to the derived type then Func of the base class will be called, not the derived class being pointed to.
How do I get around the lack of dynamic polymorphism here?
I've considered making class M a class template on the shared pointer type and having a static_cast in the constructor to ensure this type is of the base class type (A) or of a derived class.
What's the nicest way to do this? I'd prefer not to modify classes A and B to get around this problem but all suggestions are welcome.
Thanks.
Sounds like a double dispatch problem. Perhaps this would be a good place to implement the visitor pattern?
For example, create a class Evaluator, and for each T a subclass ConcreteEvaluator<T>. Give A and B methods that visit the Evaluator. Something like:
class Evaluator
{
virtual void visit_A(A* object);
virtual void visit_B(B* object);
};
template <typename T>
class ConcreteEvaluator : public Evaluator
{
public:
String* input_reference;
T& result_reference;
ConcreteEvaluator(String& input_reference_,T& result_reference_) :
input_reference(input_reference_),
result_reference(result_reference_) {}
virtual void visit_A(A* object) {
object->Func(input_reference,result_reference);
}
virtual void visit_B(B* object) {
object->Func(input_reference,result_reference);
}
}
class A
{
...
virtual void apply_evaluator(Evaluator *eval) {eval->visit_A(this);}
...
}
class B
{
...
virtual void apply_evaluator(Evaluator *eval) {eval->visit_B(this);}
...
}
For each subclass of A, a new method must be added to ConcreteEvaluator, so that this technique works best if A's class hierarchy is stable. And for each subclass of A, it must have an apply_evaluator function defined properly.
On the other hand, this may be total overkill. For about the same amount of work, you could always just pay the price to update M::Evaluate:
class M
{
...
void Evaluate(const String& sInput, T& tResult)
{
// try to downcast to each subclass of A. Be sure to check
// sub-subclasses first
try
{
dynamic_cast<B*>(pInterface.get())->Func(sInput, tResult);
return;
}
catch (std::bad_cast& ) { }
...
// nothing worked. It must really be an A
pInterface->Func(sInput,tResult);
}
...
};
I've show in the question Templatized Virtual function how to use type erasure to get some of the effects of virtual member function. Depending on what you want to do in Func(), you can use the same technique here.