Abstract class with template function issue - c++

I have an abstract struct I with method a. B and B2 will inherit from it. X struct has an I type member and will instantiate it via createInsance template method based on type. I want to have on B2 an additional function b2Exclusive but I got compilation error that it is not present in A.
error: ‘using element_type = struct B’ {aka ‘struct B’} has no member named ‘b2Exclusive’
Is any way for solving this without defining b2Exclusive for B as well and to keep to structure this way?
#include <iostream>
#include <memory>
using namespace std;
struct I
{
virtual void a() = 0;
};
struct B : public I
{
B()
{
std::cout<<"B\n";
}
void a()
{
std::cout<<"-a from B\n";
}
};
struct B2 : public I
{
B2()
{
std::cout<<"B2\n";
}
void a()
{
std::cout<<"-a from B2\n";
}
void b2Exclusive()
{
std::cout<<"-something for B2\n";
}
};
using Iptr = std::shared_ptr<I>;
struct X
{
void createI()
{
if (type == "B")
{
createInstance<B>();
}
else
{
createInstance<B2>();
}
}
template <typename T>
void createInstance()
{
auto i = std::make_shared<T>();
if (type == "B2")
{
i->b2Exclusive();
}
}
std::string type = "None";
};
int main()
{
X x;
x.type = "B2";
x.createI();
return 0;
}

You can only call b2Exclusive if the template function use typename B2: one way to do so is to create the specialization for that type, such as this for example:
struct X
{
void createI();
template <typename T>
void createInstance()
{
//do something
}
std::string type = "None";
};
template<>
void X::createInstance<B2> ()
{
auto i = std::make_shared<B2>();
i->b2Exclusive();
}
void X::createI()
{
if (type == "B")
{
createInstance<B>();
}
else
{
createInstance<B2>();
}
}
int main()
{
X x;
x.type = "B2";
x.createI();
return 0;
}

Related

How to write a void function for different Structs/Containers with a template?

For instance I have a function
void func(my_cont &C){
C.membA = 1;
C.membB = 2;
dosomething_with(C);
}
Also what to do in the function, if I have a Struct that does not have a member B?
This is a way to statically check for the existence of a membB member inside the template function.
template<typename T>
void func(T& C)
{
C.membA = 1;
if constexpr (requires() { C.membB; })
{
C.membB = 2;
}
}
int main()
{
struct A
{
int membA;
};
struct B
{
int membA;
int membB;
};
A a;
func(a);
B b;
func(b);
}
Another way to get functionality that differs per type:
Using template specialization, as OP requested.
struct A
{
int membA;
};
struct B
{
int membA;
int membB;
};
template<typename T> void func(T&);
template<> void func<A>(A& a) {
a.membA = 1;
}
template<> void func<B>(B& b) {
b.membA = 1;
b.membB = 2;
}
int main()
{
A a;
func(a);
B b;
func(b);
}

C++: How to use different dynamic template in map

my header code:
template <typename T>
class A
{
}
template<> class A<short>;
template<> class A<float>;
in my cpp, i want to use a map to contain different type a, like following code:
class B
{
map<int, A*> a; /* how to declare a */
public:
AddA(int key, int type)
{
if (type == 1)
{
a.insert({ key, new A<short>() });
}
else
{
a.insert({ key, new A<float>() });
}
}
template<typename T>
func(int key, T v)
{
a[key].func(v);
}
};
question: how to implement it?
edit # 0410, here is my solution:
class ABase
{
virtual void func(void* t)=0;
}
template <typename T> A;
template <short> A : public ABase
{
void func(void* t) override
{
auto value = *static_cast<short*>(t);
// do processing
}
template <float> A : public ABase
{
void func(void* t) override
{
auto value = *static_cast<float*>(t);
// do processing
}
CPP: used a map of ABase* for all the template class, and use a virtual func for all template interface
main()
{
map<int, ABase*> objs;
objs.insert({0, new A<short>()});
objs.insert({1, new A<float>()});
auto value=0;
objs[0]->func(&value);
auto value1=0.f;
objs[1]->func(&value1);
}
If you really need to have multiple types in a single map, you can use a map of std::variant. But as already mentioned in the comments, this might be a design problem.
But if you need it, you can proceed with the std::map< int, std::variant<>>. Later on, if you want to access the stored element, you have to call std::visit to pick the element which is stored in std::variant.
See the following example:
template < typename T >
struct A
{
};
// spezialize if needed, here only for demonstration purpose
template <> struct A<short> { void func(short parm) { std::cout << "A<short> with " << parm << std::endl; } };
template <> struct A<float> { void func(float parm) { std::cout << "A<float> with " << parm << std::endl; } };
class B
{
std::map<int, std::variant<A<short>*, A<float>*>> a;
public:
void AddA(int key, int type)
{
if (type == 1)
{
a.insert({ key, new A<short>() });
}
else
{
a.insert({ key, new A<float>() });
}
}
template<typename T>
void func(int key, T v)
{
std::visit( [&v]( auto ptr ) { ptr->func(v); }, a[key] );
}
};
int main()
{
B b;
b.AddA( 1, 1 );
b.AddA( 2, 2 );
b.func( 1, 99 );
b.func( 2, 100 );
}
You can't achieve the problem with templates. Template declaration is only a blueprint for a type candidate.
"A<short>" is the type not "A" itself.
You can achieve your problem through inheritance.
Edit: Code is updated according to #MSalters' comment. Thanks.
#include <iostream>
#include <map>
class A
{
public:
virtual void func(void* x) = 0;
};
class A_Short : public A
{
public:
void func(void* x)
{
short* value = static_cast<short*>(x);
std::cout << "short value: " << *value << std::endl;
}
};
class A_Float : public A
{
public:
void func(void* x)
{
float* value = static_cast<float*>(x);
std::cout << "float value: " << *value << std::endl;
}
};
template<typename T>
class A_Derived : public A
{
public:
void func(void* x)
{
T* value = static_cast<T*>(x);
std::cout << "[Derived] value: " << *value << std::endl;
}
};
class B
{
std::map<int, A*> a; /* how to declare a */
public:
void AddA(int key, int type)
{
if (type == 1)
{
a.insert({ key, new A_Short() });
}
else if(type == 2)
{
a.insert({key, new A_Derived<short>()});
}
else if(type == 3)
{
a.insert({key, new A_Derived<float>()});
}
else
{
a.insert({ key, new A_Float() });
}
}
// Assumes that user knows to use which T for any "key"
template<typename T>
void func(int key, T v)
{
a[key]->func(v);
}
};
int main()
{
B b;
b.AddA(1, 1);
b.AddA(2, 8);
b.AddA(3, 2);
b.AddA(4, 3);
short s = 1;
float f = 7.1;
short s2 = 2;
float f2 = 7.2;
b.func(1, &s);
b.func(2, &f);
b.func(3, &s2);
b.func(4, &f2);
}

How the base class calls the closure passed by the derived class in c++?

I have a base class, and it have a member function that sometime will be called. Usually, this function have a parameter that pointing to itself.
class Base {
public:
std::function<bool(Base *, int)> foo;
private:
int x{};
public:
static std::shared_ptr<Base> create() {
return std::make_shared<Base>();
}
Base() = default;
const std::function<bool(Base *, int)> &getFoo() const {
return foo;
}
void setFoo(const std::function<bool(Base *, int)> &foo) {
Base::foo = foo;
}
int getX() const {
return x;
}
void setX(int x) {
Base::x = x;
}
};
But when I have a derived class, how can I set this member function? Although the base class pointer can point to a subclass object, but I directly passed into the derived object, the compiler does not pass.
class Derived : public Base {
public:
static std::shared_ptr<Derived> create() {
return std::make_shared<Derived>();
}
};
int main() {
auto d = Derived::create();
d->setX(77);
d->setFoo([](Derived *derived, int x) -> bool { return derived->getX() > x; });
if (d->getFoo()) {
auto res = d->foo(d.get(), 99);
std::cout << res << std::endl;
}
return 0;
}
error: no viable conversion from '(lambda at
main.cpp:62:15)' to 'const
std::function'
b->setFoo([](Derived *derived, int x) -> bool { return derived->getX() > x; });
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
So, is there any good idea to pass a closure to base class, and base class call it instead of derived class, and the most important thing is that closure have a parameter which is point to who pass the closure!
Note
I am going to assume that for some reason the closure in question needs access to Derived's methods/data members, and the OP's example does not convey that very well. Otherwise, why not just use Base * as the input parameter:
b->setFoo([](Base *derived, int x) -> bool { return derived->getX() > x; });
#user3655463's answer contains the full code for this case.
Simple solution
In case the CRTP solution proposed by #Yuki does not work for you, you could just use Base * as an argument of the closure and static_cast it in the closure body (the compiler can optimize away the cast), like this:
int main() {
auto d = Derived::create();
d->setX(77);
d->setFoo([](Base *derived, int x) -> bool {
return static_cast<Derived *>(derived)->getX() > x;
});
if (d->getFoo()) {
auto res = d->foo(d.get(), 99);
std::cout << res << std::endl;
}
return 0;
}
Live example.
If you really need the type in the closure to be Derived *
In case having Base * in the closure is not acceptable, you could hide the setFoo method from Base with a special implementation in Derived which will do the cast for you:
class Derived : public Base {
public:
static std::shared_ptr<Derived> create() {
return std::make_shared<Derived>();
}
template <typename Closure>
void setFoo(Closure foo) {
Base::setFoo([foo](Base *base, int x) {
return foo(static_cast<Derived *>(base), x);
});
}
};
int main() {
auto d = Derived::create();
d->setX(77);
d->setFoo([](Derived *derived, int x) -> bool {
return derived->getX() > x;
});
if (d->getFoo()) {
auto res = d->foo(d.get(), 99);
std::cout << res << std::endl;
}
return 0;
}
This allows you to use the same interface as you have in your original main funciton.
Live example.
If you have a lot of derived classes, and don't want to hide that method over and over again in each class
Now things get a bit complicated, and note that it's a good chance doing something like this would be overengineering in your case, but I just want to demonstrate that it can be done - here is where CRTP comes into play. It is used to implement a mixin which provides an implementation of the setFoo method:
template <typename ConcreteDerived, typename DirectBase>
class EnableSetFooAndInherit : public DirectBase {
public:
template <typename Closure>
void setFoo(Closure foo) {
DirectBase::setFoo([foo](DirectBase *base, int x) {
return foo(static_cast<ConcreteDerived *>(base), x);
});
}
};
class Derived : public EnableSetFooAndInherit<Derived, Base> {
public:
static std::shared_ptr<Derived> create() {
return std::make_shared<Derived>();
}
};
class Derived2 : public EnableSetFooAndInherit<Derived2, Base> {
public:
static std::shared_ptr<Derived2> create() {
return std::make_shared<Derived2>();
}
};
int main() {
auto d = Derived::create();
d->setX(77);
d->setFoo([](Derived *derived, int x) -> bool {
return derived->getX() > x;
});
if (d->getFoo()) {
auto res = d->foo(d.get(), 99);
std::cout << res << std::endl;
}
auto d2 = Derived2::create();
d2->setX(77);
d2->setFoo([](Derived2 *derived, int x) -> bool {
return derived->getX() < x;
});
if (d2->getFoo()) {
auto res = d2->foo(d.get(), 99);
std::cout << res << std::endl;
}
return 0;
}
Live example.
If a template base solution fits your style then this might work.
template <typename D>
class Base {
public:
std::function<bool(D*, int)> foo;
private:
int x{};
public:
static std::shared_ptr<Base> create() { return std::make_shared<Base>(); }
Base() = default;
const std::function<bool(D*, int)>& getFoo() const { return foo; }
void setFoo(const std::function<bool(D*, int)>& foo) { Base::foo = foo; }
int getX() const { return x; }
void setX(int x) { Base::x = x; }
};
class Derived : public Base<Derived> {
public:
static std::shared_ptr<Derived> create() { return std::make_shared<Derived>(); }
};
int main() {
auto d = Derived::create();
d->setX(77);
d->setFoo([](Derived* derived, int x) -> bool { return derived->getX() > x; });
if (d->getFoo()) {
auto res = d->foo(d.get(), 99);
std::cout << res << std::endl;
}
return 0;
}
Can't you just use Base (just as you designed):
d->setFoo([](Base* derived, int x) -> bool { return derived->getX() > x; });
Whole code:
#include <algorithm>
#include <iostream>
#include <vector>
#include <functional>
#include <memory>
class Base {
public:
std::function<bool(Base *, int)> foo;
private:
int x{};
public:
static std::shared_ptr<Base> create() {
return std::make_shared<Base>();
}
Base() = default;
const std::function<bool(Base *, int)> &getFoo() const {
return foo;
}
void setFoo(const std::function<bool(Base *, int)> &foo) {
Base::foo = foo;
}
int getX() const {
return x;
}
void setX(int x) {
Base::x = x;
}
};
class Derived : public Base {
public:
static std::shared_ptr<Derived> create() {
return std::make_shared<Derived>();
}
};
int main() {
auto d = Derived::create();
d->setX(77);
d->setFoo([](Base* derived, int x) -> bool { return derived->getX() > x; });
if (d->getFoo()) {
auto res = d->foo(d.get(), 99);
std::cout << res << std::endl;
}
return 0;
}

Store different templated classes in one container without losing information about it's type

I'm currently working on a project where a client part of my application has to be able to create custom templated classes on the server. The server part has to keep track of these created classes and has to remember the types with which the classes has been instantiated. The problem is, that there are around 36 different class-template-combinations that are valid in my application. I'm currently struggling to keep track of these different types in a collection without losing information about my instances.
I'm currently using something like this:
#include <memory>
#include <type_traits>
#include <vector>
enum class data_type : std::uint8_t {
type_int = 1,
type_float,
type_double
};
enum class class_type : std:: uint8_t {
type_A = 1,
type_B
};
struct X {
virtual data_type get_data_type() = 0;
virtual class_type get_class_type() = 0;
};
template <typename T>
struct A : X {
data_type get_data_type() override
{
if (std::is_same<T, int>::value) {
return data_type::type_int;
} else if (std::is_same<T, float>::value) {
return data_type::type_float;
} else if (std::is_same<T, double>::value) {
return data_type::type_double;
} else {
/* ... */
}
}
class_type get_class_type() override
{
return class_type::type_A;
}
};
template <typename T>
struct B : X {
data_type get_data_type() override
{
if (std::is_same<T, int>::value) {
return data_type::type_int;
} else if (std::is_same<T, float>::value) {
return data_type::type_float;
} else if (std::is_same<T, double>::value) {
return data_type::type_double;
} else {
/* ... */
}
}
class_type get_class_type() override
{
return class_type::type_B;
}
};
struct Storage {
template <typename T, template <typename> class Class>
void create() {
Class<T>* t = new Class<T>();
_classes.push_back(std::unique_ptr<X>(t));
}
std::vector<std::unique_ptr<X>> _classes;
};
but I'm wondering if this is the way to go or if there is a more elegant way. Here I would have to always switch through the enums to get the full type out of my Storage class, something like:
switch(_classes.front()->get_class_type()) {
case class_type::type_A:
{
switch(_classes.front()->get_data_type()) {
case data_type::type_int:
{
/* I finally know that it is A<int> */
}
/* ... */
Thanks in advance.
You can consider using std::variant and the std::visit pattern
auto var = std::variant<int, float, double>{};
// assign var to value
std::visit([](auto& value) {
using Type = std::decay_t<decltype(value)>;
if constexpr (std::is_same<Type, int>{}) {
// is an int
} else if (std::is_same<Type, float>{}) {
// is float
} else if (std::is_same<Type, double>{}) {
// is double
}
}, var);
If the if constexpr looks ugly to you then you can substitute it with a handrolled visitor class as well.
class Visitor {
public:
void operator()(int& value) { ... }
void operator()(float& value) { ... }
void operator()(double& value) { ... }
};
auto var = std::variant<int, float, double>{};
// assign var to value
std::visit(Visitor{}, var);
As mentioned in the comments to the question, this is a viable approach that could help:
#include<vector>
#include<memory>
struct Counter {
static int next() {
static int v = 0;
return v++;
}
};
template<typename>
struct Type: Counter {
static int value() {
static const int v = Counter::next();
return v;
}
};
struct X {
virtual int get_data_type() = 0;
virtual int get_class_type() = 0;
};
template <typename T>
struct A : X {
int get_data_type() override {
return Type<T>::value();
}
int get_class_type() override {
return Type<A<T>>::value();
}
};
template <typename T>
struct B : X {
int get_data_type() override {
return Type<T>::value();
}
int get_class_type() override {
return Type<B<T>>::value();
}
};
struct Storage {
template <typename T, template <typename> class Class>
void create() {
Class<T>* t = new Class<T>();
_classes.push_back(std::unique_ptr<X>(t));
}
std::vector<std::unique_ptr<X>> _classes;
};
int main() {
Storage s;
s.create<int, A>();
if(Type<int>::value() == s._classes.front()->get_class_type()) {
//...
};
}
See it running on wandbox.

Polymorphic factory

Consider the following code:
template <typename T>
class DrawerFactory
{
protected:
DrawerFactory() {};
private:
virtual shared_ptr<IDrawer> GetDrawer(T settings) = 0;
};
class ConcreteDrawerFactoryA : public DrawerFactory<SettingsA>
{
public:
shared_ptr<IDrawer> GetDrawer(SettingsA settingsA) override
{
if (settingsA.style == A) return make_shared<ConcreteDrawerA>(settingsA.length, settingsA.stroke, settingsA.opacity);
else return make_shared<ConcreteDrawerB>(20, .5);
};
};
class ConcreteDrawerFactoryB : public DrawerFactory<SettingsB>
{
public:
shared_ptr<IDrawer> GetDrawer(SettingsB settingsB) override
{
if (settingsB.type == TYPEC) return make_shared<ConcreteDrawerC>(settingsB.width, settingsB.height);
else return make_shared<ConcreteDrawerD>(10, 2);
};
};
I can get a drawer by:
ConcreteDrawerFactoryA().GetDrawer(settingsa);
or
ConcreteDrawerFactoryB().GetDrawer(settingsb);
What I'd like to do is:
DrawerFactory().GetDrawer(settingsa);
DrawerFactory().GetDrawer(settingsb);
Is there a way to set this up without having to continually add overloads to DrawerFactory for each concrete factory I want to add?
Instead of factory hierarchy and virtual dispatch you could make use of templates and specialization:
#include <memory>
struct IDrawer { };
struct Drawer1: IDrawer { };
struct Drawer2: IDrawer { };
struct Drawer3: IDrawer { };
struct Drawer4: IDrawer { };
template <class T>
struct DrawerGetterImpl;
struct DrawerFactory {
template <class T>
std::shared_ptr<IDrawer> GetDrawer(T settings) {
return DrawerGetterImpl<T>::GetDrawer(settings);
}
};
struct SettingsA { int style; };
template <>
struct DrawerGetterImpl<SettingsA> {
static std::shared_ptr<IDrawer> GetDrawer(SettingsA settings) {
if (settings.style == 1) {
return std::make_shared<Drawer1>();
}
return std::make_shared<Drawer2>();
}
};
struct SettingsB { int type; };
template <>
struct DrawerGetterImpl<SettingsB> {
static std::shared_ptr<IDrawer> GetDrawer(SettingsB settings) {
if (settings.type == 1) {
return std::make_shared<Drawer3>();
}
return std::make_shared<Drawer4>();
}
};
int main() {
DrawerFactory().GetDrawer(SettingsA{1});
}
[live demo]
In your example, your factory seemed to have no state, so can you achieve what you want without a polymorphic factory? For example something like this...
template<class T>
std::shared_ptr<IDrawer> MakeDrawer(T settings);
template<>
std::shared_ptr<IDrawer> MakeDrawer<SettingsA>(SettingsA settings)
{
return std::make_shared<ConcreteDrawerA>(); // use settings really
}
template<>
std::shared_ptr<IDrawer> MakeDrawer<SettingsB>(SettingsB settings)
{
return std::make_shared<ConcreteDrawerB>(); //use settings here
}
void main()
{
SettingsA setA;
std::shared_ptr<IDrawer> pA = MakeDrawer(setA);
SettingsB setB;
std::shared_ptr<IDrawer> pB = MakeDrawer(setB);
}
You could use overloads instead of templates.