I have base class and a bunch of derived classes (only one here for simplicity). I also have holder class with one of derived classes as a template argument. I want holder object to create an instance of derived class. Here is the code:
class base {
protected:
int value;
public:
base() : value (0) { }
base(int value) : value(value) { }
};
class derived : public base { };
template <class T>
class holder {
public:
holder(T) {}
T create(int value) {
return T(value);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
holder<base*> h(&derived());
derived* d = h.create(1); // error here
}
I get an error error C2440: 'initializing' : cannot convert from 'base *' to 'derived *'. I guess that's because type of variable is holder<base*>, so create method is called with base as template argument. But how do I cast it properly if I have a lot of derived classes?
UPD.
I changed holder::create method so it uses std::remove_pointer but I still get the same compile error.
T create(int value) {
return new (std::remove_pointer<T>::type)(value);
}
You can let holder holds derived type rather than base type, and use boost::any or std::any (c++ 17) to store all the holders.
#include "iostream"
#include "boost/any.hpp"
#include "vector"
class base {
protected:
int value;
public:
base() : value (0) { }
base(int value) : value(value) { }
};
class derived1 : public base {
public:
derived1(int value) : base(value) {};
};
class derived2 : public base {
public:
derived2(int value) : base(value) {};
};
template <class T>
class holder {
public:
holder() {}
T* create(int value) {
return new T(value);
}
};
int main()
{
std::vector<boost::any> list;
holder<derived1> h1;
holder<derived2> h2;
list.push_back(h1);
list.push_back(h2);
derived1* pd1 = boost::any_cast<holder<derived1>>(list[0]).create(1);
derived2* pd2 = boost::any_cast<holder<derived2>>(list[1]).create(2);
}
Related
I am trying to figure out how to resolve an ambiguity problem with function names in base classes.
#include <type_traits>
template <typename T, typename PARENT>
class BaseA
{
public:
BaseA(PARENT& p) : _parent(p) {}
public:
template <typename P_ = PARENT>
auto& parent() {
if constexpr (std::is_same_v<P_, PARENT>) {
return _parent;
} else {
return _parent.template parent<P_>();
}
}
private:
PARENT& _parent;
};
class AbstractBaseB {
};
class BaseB : public AbstractBaseB
{
public:
AbstractBaseB* parent() { return _parent; }
private:
AbstractBaseB* _parent;
};
class Z {
public:
void foo() {}
};
class Y : public BaseA<Y, Z>, public BaseB
{
public:
Y(Z& z) : BaseA(z) {
}
void foo() {}
};
class X : public BaseA<X, Y>, public BaseB
{
public:
X(Y& y) : BaseA(y) {
//This will compile
BaseA::parent().foo();
//This will NOT compile
BaseA::parent<Z>().foo();
}
};
int main()
{
Z z;
Y y(z);
X x(y);
}
This is a very specific/odd use case, so I have a working example here:
https://cppinsights.io/s/08afbad9
To get it to compile, just comment out line 58. With 58 enabled, this is where I get the ambiguity which is due to line 16:
return _parent.template parent<P_>();
Since _parent is of a different type than this instance of the BaseA template, I can't just do:
return _parent.template BaseA::parent<P_>();
like I did on line 57.
How do I go about fixing this?
For those who ask, the purpose of the templated parent method is to get the "Nth" nested parent without having to do something like parent().parent().parent()
If you want member function (templates) of the same name to be considered from multiple base classes you need to explicitly import them into the derived class scope:
class Y : public BaseA<Y, Z>, public BaseB
{
public:
/*...*/
using BaseA::parent;
using BaseB::parent;
};
I am trying to understand the behavior of "Type Erasure" by using std::make_shared. The basic idea is to use a class Object to wrap some different classes, such as class Foo and class Bar.
I write the following code, and it does work.
// TypeErasure.cpp
#include <iostream>
#include <memory>
#include <string>
#include <vector>
class Base
{
public:
virtual ~Base() {}
virtual std::string getName() const = 0;
};
template< typename T >
struct Derived : Base
{
public:
explicit Derived(const T&& t) : objD(t) {}
std::string getName() const override
{
return objD.getName();
}
private:
T objD;
};
class Object
{
public:
template <typename T>
explicit Object(T&& t)
: objPtr(std::make_shared<Derived<T>>(std::forward<T>(t))) {}
std::string getName() const
{
return objPtr->getName();
}
std::shared_ptr<const Base> objPtr;
};
void printName(std::vector<Object> vec)
{
for (auto v: vec) std::cout << v.getName() << std::endl;
}
class Bar
{
public:
std::string getName() const
{
return "Bar";
}
};
class Foo
{
public:
std::string getName() const
{
return "Foo";
}
};
int main()
{
std::vector<Object> vec{Object(Foo()), Object(Bar())};
printName(vec);
}
but when I change "struct Derived : Base" into "class Derived : Base", it shows the following error.
error: no matching function for call to 'std::shared_ptr::shared_ptr(std::shared_ptr)'|
The code is as following.
// TypeErasure.cpp
#include <iostream>
#include <memory>
#include <string>
#include <vector>
class Base
{
public:
virtual ~Base() {}
virtual std::string getName() const = 0;
};
template< typename T >
class Derived : Base
{
public:
explicit Derived(const T&& t) : objD(t) {}
std::string getName() const override
{
return objD.getName();
}
private:
T objD;
};
class Object
{
public:
template <typename T>
explicit Object(T&& t)
: objPtr(std::make_shared<Derived<T>>(std::forward<T>(t))) {}
std::string getName() const
{
return objPtr->getName();
}
std::shared_ptr<const Base> objPtr;
};
void printName(std::vector<Object> vec)
{
for (auto v: vec) std::cout << v.getName() << std::endl;
}
class Bar
{
public:
std::string getName() const
{
return "Bar";
}
};
class Foo
{
public:
std::string getName() const
{
return "Foo";
}
};
int main()
{
std::vector<Object> vec{Object(Foo()), Object(Bar())};
printName(vec);
}
What is the root cause of this error?
Is it about the difference between class and struct?
Is it because class is a reference and struct is a value?
The only real difference between a class and a struct in C++ is that, for a struct, the default member access and inheritance is public, whereas, for a class, the default is private.
So, to make your code work for the class Derived template, just make its inheritance of Base public:
template< typename T >
class Derived : public Base { // public inheritance
public:
//...
Such public inheritance gives the Derived class access to the Base class constructors.
Alternatively, to make your struct template case fail – most likely with the exact same error message(s) – you can make its inheritance of Base private:
template< typename T >
struct Derived : private Base { // private inheritance - fails to compile!
public:
//...
I have a base class B with derived classes X, Y and Z (in fact, more than 20 derived classes). Each class has a tag() function that identifies which (derived) class it is. My program stores instances of the derived classes as pointers in a vector defined as vector<B*>. Each derived class may appear in this vector 0..n times.
I would like to have a function that looks through the vector for instances of a derived type and returns a new vector with the type of the derived class, eg
#include <vector>
using namespace std;
class B {
public:
// ...
virtual int tag() {return 0xFF;};
};
class X : public B {
// ...
int tag() {return 1;};
vector<X*> find_derived(vector<B*> base_vec) {
vector<X*> derived_vec;
for (auto p : base_vec) {
if (p->tag() == tag()) {
derived_vec.push_back((X*) p);
}
}
return derived_vec;
}
};
Obviously I don't want to have to define find_derived in each derived class but I don't see how to do this as a virtual function. Currently I am doing it using a macro but, since I am learning C++, I woudl prefer a method that used language constructs rather than those in the pre-processor. Is there another way?
One possibility:
template <typename D>
class FindDerivedMixin {
public:
vector<D*> find_derived(const vector<B*>& base_vec) {
int my_tag = static_cast<D*>(this)->tag();
vector<D*> derived_vec;
for (auto p : base_vec) {
if (p->tag() == my_tag) derived_vec.push_back(static_cast<D*>(p));
}
return derived_vec;
}
};
class X : public B, public FindDerivedMixin<X> {};
Like the previous answer, what you need is some template programming.
This is an example without mixin though:
#include <vector>
#include <iostream>
#include <type_traits>
#include <string>
//-----------------------------------------------------------------------------
// Base class
class Base
{
public:
virtual ~Base() = default;
// pure virtual method to be implemented by derived classes
virtual void Hello() const = 0;
protected:
// example of a constuctor with parameters
// it is protected since no instances of Base
// should be made by accident.
explicit Base(const std::string& message) :
m_message(message)
{
}
// getter for private member variable
const std::string& message() const
{
return m_message;
}
private:
std::string m_message;
};
//-----------------------------------------------------------------------------
// Class which contains a collection of derived classes of base
class Collection
{
public:
Collection() = default;
virtual ~Collection() = default;
// Add derived classes to the collection.
// Forward any arguments to the constructor of the derived class
template<typename type_t, typename... args_t>
void Add(args_t&&... args)
{
// compile time check if user adds a class that's derived from base.
static_assert(std::is_base_of_v<Base, type_t>,"You must add a class derived from Base");
// for polymorphism to work (casting) we need pointers to derived classes.
// use unique pointers to ensure it is the collection that will be the owner of the
// instances
m_collection.push_back(std::make_unique<type_t>(std::forward<args_t>(args)...));
}
// Getter function to get derived objects of type_t
template<typename type_t>
std::vector<type_t*> get_objects()
{
static_assert(std::is_base_of_v<Base, type_t>, "You must add a class derived from Base");
// return non-owning pointers to the derived classes
std::vector<type_t*> retval;
// loop over all objects in the collection of type std::unique_ptr<Base>
for (auto& ptr : m_collection)
{
// try to cast to a pointer to derived class of type_t
type_t* derived_ptr = dynamic_cast<type_t*>(ptr.get());
// if cast was succesful we have a pointer to the derived type
if (derived_ptr != nullptr)
{
// add the non-owning pointer to the vector that's going to be returned
retval.push_back(derived_ptr);
}
}
return retval;
}
private:
std::vector<std::unique_ptr<Base>> m_collection;
};
//-----------------------------------------------------------------------------
// some derived classes for testing.
class Derived1 :
public Base
{
public:
explicit Derived1(const std::string& message) :
Base(message)
{
}
virtual ~Derived1() = default;
void Hello() const override
{
std::cout << "Derived1 : " << message() << "\n";
}
};
//-----------------------------------------------------------------------------
class Derived2 :
public Base
{
public:
explicit Derived2(const std::string& message) :
Base(message)
{
}
virtual ~Derived2() = default;
void Hello() const override
{
std::cout << "Derived2 : " << message() << "\n";
}
};
//-----------------------------------------------------------------------------
int main()
{
Collection collection;
collection.Add<Derived1>("Instance 1");
collection.Add<Derived1>("Instance 2");
collection.Add<Derived2>("Instance 1");
collection.Add<Derived2>("Instance 2");
collection.Add<Derived1>("Instance 3");
// This is where template programming really helps
// the lines above where just to get the collection filled
auto objects = collection.get_objects<Derived1>();
for (auto& derived : objects)
{
derived->Hello();
}
return 0;
}
I have the following situation, where I want to instantiate an object of a template type.
I want the instantiation of the template type object to depend on the "instantiator" class.
template <class T>
class Base
{
public:
Base(){}
void do_something()
{
T obj = this->Test();
// do something with object
}
virtual T Test()
{
return T(5);
}
};
template <class T>
class Derived : public Base<T>
{
public:
Derived() : Base<T>() {}
virtual T Test()
{
return T(5, 6);
}
};
class Test1
{
public:
Test1(int x){}
};
class Test2 : public Test1
{
public:
Test2(int x, int y) : Test1(x) {}
};
Later in my code I want to work with Base or Derived objects.
They perform operations on a template type object (obj) in function do_something().
I want to let the instantiation of obj depend on the implementation
of the Test() function.
Base should only work with objects of type Test1 or derived classes of Test1 that have the same constructor.
Derived should only work on objects that have the same constructor as Test2.
Base<Test1>(); // works
Base<Test2>(); // doesn't work, but should not work by my design and throw a compile error
Derived<Test1>(); // same
Derived<Test2>(); // should work, but doesn't,
// since Base::Test() still exists, but cannot be compiled due to wrong constructor of T
Is there a way to implement the described behavior?
Or is there a design change I can make?
You might change Base to be correct for any T:
template <class T>
class Base
{
public:
Base(){}
void do_something()
{
T obj = this->Test();
// do something with object
}
virtual T Test()
{
if constexpr (std::is_constructible_v<T, int>) {
return T(5);
}
throw std::runtime_error("should not be called");
}
};
but
Base<Test2>(); would compile but throw at runtime.
Seems better to split and have two derived:
template <class T>
class Base
{
public:
Base() = default;
virtual ~Base() = default;
void do_something()
{
T obj = this->Test();
// do something with object
}
virtual T Test() = 0;
};
template <class T>
class Derived : public Base<T>
{
public:
Derived() : Base<T>() {}
T Test() override { return T(4); }
};
template <class T>
class Derived2 : public Base<T>
{
public:
Derived() : Base<T>() {}
T Test() override { return T(5, 6); }
};
I have this code which I think should work, but it is not!
class base
{
std::array<uint8_t, 8> m_ID;
public:
base(std::array<uint8_t, 8> id) :m_ID(id)
{
}
}
template<char ...Ts>
class derived:base(Ts...)
{
}
class MyClass: public derived<'1','2','3','4','5','6','7','8'>
{
}
How can I do this? The idea is that I can pass the ID value from template values.
I am getting error that MyClass is not complete. (Incomplete type is not allowed)
You just have to call the base class constructor properly:
#include <array>
#include <cstdint>
class base
{
std::array<std::uint8_t, 8> m_ID;
public:
base(std::array<std::uint8_t, 8> id) :m_ID(id)
{
}
};
template<char ...Ts>
class derived: public base
{
public:
derived() : base{ { Ts... } } { }
};
class MyClass: public derived<'1','2','3','4','5','6','7','8'>
{
};
int main() {
MyClass d;
}
Note that in the constructor initializer list, the inner pair of braces is needed to convert the single uint8_ts to an array.