Recursively getting item from nested generic data structure - c++

I'm trying to build a generic container class using templates so that I can store an arbitrary data type in the container. I have a generic interface class with a virtual "get" method that returns an object of the parametrized type. One common use of this container will be to create a "container-of-containers" with 2 or more levels. What I'd like to do is provide a recursive "get" method that will traverse the hierarchy and return an item from a leaf node.
Here is some example code showing what I'm trying to do:
#include <iostream>
template<typename DataT>
class container_intf
{
public:
container_intf() = default;
virtual ~container_intf() = default;
virtual DataT get() = 0;
};
class one : public container_intf<int>
{
public:
int get() { return 1; };
};
class two : public container_intf<int>
{
public:
int get() { return 2; };
};
template<typename DataT>
class generic : public container_intf<DataT>
{
public:
DataT get()
{
return DataT();
};
};
int main(int argc, char** argv)
{
one o;
two t;
std::cout << o.get() << "\n";
std::cout << t.get() << "\n";
generic<int> g;
std::cout << g.get() << "\n";
generic<one> one_nested;
std::cout << one_nested.get().get() << "\n";
generic< generic<two> > two_nested;
std::cout << two_nested.get().get().get() << "\n";
return 0;
};
Basically, I'd like to be able to call "two_nested.get()" instead of "two_nested.get().get().get()". I've tried using type traits and std::enable_if but I haven't been able to get it to work. A helper class or function would be fine; I just want to be able to support a hierarchy of arbitrary depth.

Wouldn't return DataT().get() in the function generic<DataT>::DataT get() solve the issue?
I mean the following class definition:
template<typename DataT>
class generic : public container_intf<DataT>
{
public:
//if using c++14, you can use just `auto` as a return type
decltype (DataT::get()) get()
{
return DataT().get(); //< instead of just `return DataT();`
};
};

Related

How can I return an arbitrary derived class of an abstract generic class and call its generic methods?

I've got an abstract class that uses variable template.
template <class T>
class Abstract
{
public:
virtual void print(T t) = 0;
};
There can be any derivatives of the class like so:
class A : public Abstract<std::string>
{
public:
void print(std::string str)
{
std::cout << str << std::endl;
}
};
class B : public Abstract<int>
{
public:
void print(int number)
{
std::cout << std::to_string(number) << std::endl;
}
};
Now I want a function to return one of these derivatives so I can execute the print method. And here is my Problem:
template (class T); // error here
Abstract<T> &f(int n) // what should the return type look like?
{
if (n == 0)
{
A a{};
return a;
}
else
{
B b{};
return b;
}
}
int main()
{
A a{f(0)};
a.print("foo");
B b{f(1)};
b.print(42);
return 0;
}
So how is it be possible to return a class with unknown parameter type and call its methods?
I already tried returning derived classes without templates which works fine. As soon as templates are added code wont compile. I also tried void* and reinterpret_cast. Problem here is that I have manually to decide to what type to cast to.
So how can I return an arbitrary superclass of an abstract generic class and call its generic methods?
I think inheritance is the wrong approach here. Instead I would use specialization instead:
template<typename T>
struct Foo;
template<>
struct Foo<std::string>
{
void print(std::string const& s)
{
std::cout << s << '\n';
}
};
template<>
struct Foo<int>
{
void print(int value)
{
std::cout << value << '\n';
}
};
Then you don't need a selector to pick the object to create, just the correct type:
int main()
{
Foo<std::string> f1;
f1.print("hello");
Foo<int> f2;
f2.print(123);
}
If you really need a factor function, then it could be created like this:
template<typename T>
Foo<T> create()
{
return Foo<T>();
}
And use like
int main()
{
auto f1 = create<std::string>();
f1.print("hello");
auto f2 = create<int>();
f2.print(123);
}

How can you iterate over elements of a std::tuple with a shared base class?

Assume you have a std::tuple with a common base class:
class MyBase { public: virtual int getVal() = 0; };
class MyFoo1: public MyBase { public: int getVal() override { return 101; } };
class MyFoo2: public MyBase { public: int getVal() override { return 202; } };
using MyTuple = std::tuple<MyFoo1, MyFoo2, MyFoo1>;
How do you iterate over the elements of the tuple at runtime? The usual answer is that you can't because they all have different types, but here I'm happy for a static type of MyBase*. I'm hoping for code like this:
MyTuple t;
for (Base* b : iterate_tuple<MyBase>(t)) {
std::cout << "Got " << b->getVal() << "\n";
}
There are a lot of helpful ideas over at How can you iterate over the elements of an std::tuple?, but they all include the code to run at each iteration in the fiddly template code, whereas I'd like all the fiddly template code bundled into the hypothetical iterate_tuple function so my code is just a normal for loop.
Here's a little wrapper function that gets the tuple value by index, specified at runtime, which does a linear search for the right index by recursively calling itself with a different template parameter. You specify its return type as a template parameter, and the value gets implicitly converted to it.
template <class BaseT, class TupleT, size_t currentIndex = 0>
BaseT* getBasePtr(TupleT& t, size_t desiredIndex) {
if constexpr (currentIndex >= std::tuple_size<TupleT>::value) {
return nullptr;
}
else {
if (desiredIndex == currentIndex) {
return &std::get<currentIndex>(t);
}
else {
return getBasePtr<BaseT, TupleT, currentIndex + 1>(t, desiredIndex);
}
}
}
You can then use it in a loop over the indices of the tuple:
for (size_t i = 0; i < std::tuple_size<MyTuple>::value; ++i) {
MyBase* b = getBasePtr<MyBase>(t, i);
std::cout << "At " << i << " got " << b->getVal() << "\n";
}
It's not quite as neat as a range-based for loop but it's still pretty straightforward to use. (You could wrap it in an iterator class that would support range-based loops but I don't really think it's worth the effort.)
As mentioned and suggested in the question linked to using std::apply is a good way to get each individual element of the tuple.
Making a small helper function to wrap the forwarding of each tuple element makes it easy to use.
It's not the specific for-loop syntax you asked for, but it's as easy to follow if you ask me.
#include <tuple>
#include <utility>
#include <iostream>
class MyBase { public: virtual int getVal() = 0; };
class MyFoo1: public MyBase { public: int getVal() override { return 101; } };
class MyFoo2: public MyBase { public: int getVal() override { return 202; } };
using MyTuple = std::tuple<MyFoo1, MyFoo2, MyFoo1>;
template <typename Tuple, typename Callable>
void iterate_tuple(Tuple&& t, Callable c) {
std::apply([&](auto&&... args){ (c(args), ...); }, t);
}
int main() {
MyTuple t;
iterate_tuple(t, [](auto& arg) {
std::cout << "Got " << arg.getVal() << "\n";
});
iterate_tuple(t, [](MyBase& arg) {
std::cout << "Got " << arg.getVal() << "\n";
});
}
We can get the exact type by using auto or use the common base type.
As Sam suggests in the comments, it's quite simple to create an array from a tuple.
template<typename Base, typename Tuple, size_t... Is>
std::array<Base *, std::tuple_size_v<Tuple>> iterate_tuple_impl(Tuple& tuple, std::index_sequence<Is...>)
{
return { std::addressof(std::get<Is>(tuple))... };
}
template<typename Base, typename Tuple>
std::array<Base *, std::tuple_size_v<Tuple>> iterate_tuple(Tuple& tuple)
{
return iterate_tuple_impl(tuple, std::make_index_sequence<std::tuple_size_v<Tuple>>{});
}
If you have inheritance, why not to do without tuple and use inheritance capabilities like this:
#include <iostream>
#include <vector>
class MyBase { public: virtual int getVal() = 0; };
class MyFoo1 : public MyBase { public: int getVal() override { return 101; } };
class MyFoo2 : public MyBase { public: int getVal() override { return 202; } };
int main() {
std::vector<std::unique_ptr<MyBase>> base;
base.emplace_back(new MyFoo1);
base.emplace_back(new MyFoo2);
for (auto && derived : base) {
std::cout << derived->getVal() << std::endl;
}
}
I would directly use std::apply, but you can create array of Base*:
template <typename Base, typename Tuple>
std::array<Base*, std::tuple_size<Tuple>> toPtrArray(Tuple& tuple)
{
return std::apply([](auto& ... args){ return std::array<Base*, std::tuple_size<Tuple>>{{&args}}; }, tuple);
}
And then
MyTuple t;
for (Base* b : toPtrArray<MyBase>(t)) {
std::cout << "Got " << b->getVal() << "\n";
}

CRTP vs. vector of base class

I have an issue similar to this C++ vector of CRTP shared pointers but my problem formulation adds the fact that the return type of a function i want to use for all inheriting classes is templated.
In detail lets assume this :
template <class Derived>
class Base {
Derived Value() const {
return static_cast<Derived>(this->Value());
};
};
class ChildDouble : public Base<ChildDouble> {
public:
ChildDouble(double r) : _value(r){};
double Value() const {
return _value;
};
private:
double _value;
};
class ChildString : public Base<ChildDouble> {
public:
ChildString(string s) : _value(s){};
string Value() const {
return _value;
};
private:
string _value;
};
Goal would be to use it somewhat similar as in the following main
void main() {
std::vector<Base*> vec;
vec.push_back(new ChildDouble(3.0));
vec.push_back(new ChildString("Thomas"));
unsigned counter = 0;
for (const auto& e : vec) {
std::cout << "Entry " << counter << " : " << e->Value()
<< std::endl;
counter++;
}
}
The compiler is obviously not happy with this because Base requires a template argument.
Any Ideas how this could be solved? AM I using CRTP here although i should not be using it?
Virtual methods (which is what you'd normally need to get the above working without CRTP) won't work here because the interface is different for Value() in each derived type. Virtual inheritance depends on the signature being the same for everyone, except in a few special cases like with covariant return types. It also won't work because virtual methods can't be templated.
But, you can use std::variant to dynamically dispatch your incompatible interfaces, because it is based on templates. First, define a convenient alias for your variant:
using Child = std::variant<ChildDouble, ChildString>;
And then to use, dispatch with std::visit and a generic lambda:
std::vector<Child> vec;
vec.push_back(ChildDouble(3.0));
vec.push_back(ChildString("Thomas"));
unsigned counter = 0;
for (const auto& e : vec) {
std::visit([&counter](auto&& v) {
std::cout << "Entry " << counter << " : " << v.Value()
<< std::endl;
}, e);
counter++;
}
Demo: https://godbolt.org/z/bENWYW
It doesn't work because the compiler doesn't know which type you want to put in the vector and you need to specified it. If you try vector<Base<double>*>vec; it will works but you can't use the vector with other types like Base, because, it is other type.
The solution is to use std::variant or std::any in place of template.
Now you have an object variant/any the declare value in base will make your life easier.
Also I suggest you:
not to use variables starting with underline '_' because this syntax is used by many internal function of compiler.
not to use raw pointer. use smart_ptr like share_ptr then you don't need to worry to destroy it with delete.
Below the code with the changes:
#include <memory>
#include <vector>
#include <string>
#include <variant>
#include <iostream>
using namespace std;
struct Base {
Base(variant<double, string> val) : value(val) {}
void Print() { //just to ilustrate how it works. Better use ostream
if (holds_alternative<double>(this->value))
cout << get<double>(this->value);
else if (holds_alternative<string>(this->value))
cout << get<string>(this->value);
}
protected:
variant<double, string> value;
variant<double, string> BaseValue() const { return this->value; };
};
struct ChildDouble : public Base {
ChildDouble(double r) : Base(r) {};
double Value() const { return get<double>(this->BaseValue()); }
};
struct ChildString : public Base {
ChildString(string s) : Base(s) {};
string Value() const { return get<string>(this->BaseValue()); };
};
int main() { //must return int not void
vector<shared_ptr<Base>>vec;
vec.emplace_back(new ChildDouble(3.0));
vec.emplace_back(new ChildString("Thomas"));
unsigned counter = 0;
for (const auto& e : vec) {
cout << "Entry " << counter << " : "; e->Print(); cout << endl;
++counter;
}
}

Calling parametrised method on list items with different template parameters

I'm trying to store and manipulate a list of template class objects with different parameter types; the template class has two parametrised methods, one returning the parameter type and a void one accepting it as input.
More specifically, I have a template class defined as follows:
template<typename T>
class Test
{
public:
virtual T a() = 0;
virtual void b(T t) = 0;
};
And different specifications of it, such as:
class TestInt : public Test<int>
{
public:
int a() {
return 1;
}
void b(int t) {
std::cout << t << std::endl;
}
};
class TestString : public Test<std::string>
{
public:
std::string a() {
return "test";
}
void b(std::string t) {
std::cout << t << std::endl;
}
};
I'd like to be able to store in one single list different objects of both TestInt and TestString type and loop through it calling one method as input for the other, as in:
for (auto it = list.begin(); it != list.end(); ++it)
(*it)->b((*it)->a());
I've looked into boost::any but I'm unable to cast the iterator to the specific class, because I don't know the specific parameter type of each stored object. Maybe this cannot be done in a statically typed language as C++, but I was wondering whether there could be a way around it.
Just for the sake of completeness, I'll add that my overall aim is to develop a "parametrised observer", namely being able to define an observer (as with the Observer Pattern) with different parameters: the Test class is the observer class, while the list of different types of observers that I'm trying to properly define is stored within the subject class, which notifies them all through the two methods a() and b().
The virtuals have actually no meaning here, since for each T the signatures are distinct.
So it seems you have Yet Another version of the eternal "how can we emulate virtual functions templates" or "how to create an interface without virtual functions":
Generating an interface without virtual functions?
How to achieve "virtual template function" in C++
The first one basically contains an idea that you could employ here.
Here's an idea of what I'd do:
Live On Coliru
#include <algorithm>
#include <iostream>
namespace mytypes {
template <typename T>
struct Test {
T a() const;
void b(T t) { std::cout << t << std::endl; }
};
template <> int Test<int>::a() const { return 1; }
template <> std::string Test<std::string>::a() const { return "test"; }
using TestInt = Test<int>;
using TestString = Test<std::string>;
}
#include <boost/variant.hpp>
namespace mytypes {
using Value = boost::variant<int, std::string>;
namespace detail {
struct a_f : boost::static_visitor<Value> {
template <typename T>
Value operator()(Test<T> const& o) const { return o.a(); }
};
struct b_f : boost::static_visitor<> {
template <typename T>
void operator()(Test<T>& o, T const& v) const { o.b(v); }
template <typename T, typename V>
void operator()(Test<T>&, V const&) const {
throw std::runtime_error(std::string("type mismatch: ") + __PRETTY_FUNCTION__);
}
};
}
template <typename O>
Value a(O const& obj) {
return boost::apply_visitor(detail::a_f{}, obj);
}
template <typename O, typename V>
void b(O& obj, V const& v) {
boost::apply_visitor(detail::b_f{}, obj, v);
}
}
#include <vector>
int main()
{
using namespace mytypes;
using AnyTest = boost::variant<TestInt, TestString>;
std::vector<AnyTest> list{TestInt(), TestString(), TestInt(), TestString()};
for (auto it = list.begin(); it != list.end(); ++it)
b(*it, a(*it));
}
This prints
1
test
1
test
Bonus Points
If you insist, you can wrap the AnyTest variant into a proper class and have a() and b(...) member functions on that:
Live On Coliru
int main()
{
using namespace mytypes;
std::vector<AnyTest> list{AnyTest(TestInt()), AnyTest(TestString()), AnyTest(TestInt()), AnyTest(TestString())};
for (auto it = list.begin(); it != list.end(); ++it)
it->b(it->a());
}
Expanding on my comment above, the simplest what I can currently think of to achieve what you are trying to do - at least as I understood it from your example code - is the following:
/* Interface for your container, better not forget the destructor! */
struct Test {
virtual void operate(void) = 0;
virtual ~Test() {}
};
/* Implementation hiding actual type */
template<typename T>
struct TestImpl : public T, public Test {
void operate(void) {
T::b(T::a());
}
};
/* Actual code as template policies */
struct IntTest {
int a(void) {
return 42;
}
void b(int value) {
std::cout << value << std::endl;
}
};
struct StringTest {
std::string a(void) {
return "Life? Don't talk to me about life.";
}
void b(std::string value) {
std::cout << value << std::endl;
}
};
You would then need to create a container for objects of class Test and fill it with objects of the respective TestImpl<IntTest>, TestImpl<StringTest>, and so on. To avoid object slicing you need reference or pointer semantics, that is std::vector<std::unique_ptr<Test> > for example.
for (auto it = list.begin(); it != list.end(); ++it) {
(*it)->operate();
}

C++ How to build generic Products in a Factory

I'm trying to figure out a way to solve the following problem (stripped down version of the actual code, sorry for the obvious memory leaks):
#include <iostream>
namespace A {
struct Product {
virtual void doSomething() const =0;
};
template<typename T>
struct SpecialProduct : public Product {
T t;
SpecialProduct(T t) : t(t) {};
virtual void doSomething() const { std::cout << "A: " << t << " does something\n"; }
};
struct Factory {
template<typename T>
Product* create(T t = T()) const { return new SpecialProduct<T>(t); }
};
}
namespace B {
struct Product {
virtual void doSomething() const =0;
};
template<typename T>
struct SpecialProduct : public Product {
T t;
SpecialProduct(T t) : t(t) {};
virtual void doSomething() const { std::cout << "B: " << t << " does something\n"; }
};
struct Factory {
template<typename T>
Product* create(T t = T()) const { return new SpecialProduct<T>(t); }
};
}
struct ProductType { };
template<typename T>
struct SpecialProductType : public ProductType {};
int main() {
// I have a factory of a known type
A::Factory f;
// standard procedure
A::Product* p = f.create<int>();
p->doSomething();
// I have a product type description from some source
ProductType* t = /* some source */ 0;
// How do i get a product instance of type t from f?
// A::Product* p = f. ???
}
I have multiple implementations of a module, in this case within different namespaces. The factory pattern is utilized to handle the variants. Each module offers (abstract) Products and specialized generic versions. Product types are represented using a uniform class infrastructure following the same pattern.
My problem is: given a pointer to a specialized product type, how can I implement a function producing an instance of a correspondingly specialized product from a given factory object?
Thanks a lot for any advice.
After working on it for a few days I came up with the following solution:
#include <iostream>
#include <functional>
#include <typeinfo>
#include <typeindex>
#include <map>
#include <string>
using namespace std;
struct ProductType {
type_index type;
ProductType(type_index type) : type(type) {}
};
template<typename T>
struct SpecialProductType : public ProductType {
SpecialProductType() : ProductType(typeid(T)) {}
};
template<typename Derived, typename _product_type>
struct FactoryBase {
typedef _product_type product_type;
map<type_index, function<product_type*()>> creators;
template<typename T>
void addProductType() {
creators[typeid(T)] = [&]()->product_type* {
static_cast<Derived*>(this)->template create<T>();
};
}
product_type* createForType(const ProductType& type) {
return creators[type.type]();
}
};
namespace A {
struct Product {
virtual void doSomething() const =0;
};
template<typename T>
struct SpecialProduct : public Product {
T t;
SpecialProduct(T t = T()) : t(t) {};
virtual void doSomething() const { std::cout << "A: " << typeid(T).name() << " does something\n"; }
};
struct Factory : public FactoryBase<Factory,Product> {
typedef Product product_type;
template<typename T>
Product* create() const {
std::cout << "A is creating a product of type " << typeid(T).name() << "\n";
return new SpecialProduct<T>();
}
};
}
namespace B {
struct Product {
virtual void doSomething() const =0;
};
template<typename T>
struct SpecialProduct : public Product {
T t;
SpecialProduct(T t = T()) : t(t) {};
virtual void doSomething() const { std::cout << "B: " << typeid(T).name() << " does something\n"; }
};
struct Factory : public FactoryBase<Factory,Product> {
typedef Product product_type;
template<typename T>
Product* create() const {
std::cout << "B is creating a product of type " << typeid(T).name() << "\n";
return new SpecialProduct<T>();
}
};
}
int main() {
// I have a factory of a known type
A::Factory f;
f.addProductType<float>();
f.addProductType<string>();
ProductType* tf = new SpecialProductType<float>();
ProductType* ts = new SpecialProductType<string>();
f.createForType(*tf)->doSomething();
f.createForType(*ts)->doSomething();
}
Essentially I'm building my own dynamic dispatcher table based on the type of product to be created within the FactoryBase class. The key is the generic type, the value a functor capable of creating a proper instance.
The downside of the presented solution is the requirement of registering a list of supported types - but this can be done without altering the code of the factories or the product types (open/close principle). Any user code can dynamically extend the list of supported product types.