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;
}
}
Related
I am trying to create a compile time polymorphism design that will not require virtual functions with all their drawbacks. However I am struggling with creating simple, effective and easy to understand container that can simulate the ability to hold derived class in it's base class container. My previous attempts with compile time variadic vectors were working, but the code was huge mess. This solutions seems cleaner to me. I have simple code that implements basic CTRP. However I created a runtime container that is storing std::any objects and then based on the type of the object, I can define the action that is supposed to be taken. I have few questions.
How does the usage of std::any and subsequent any_cast<>() hinder the performance compared to the usage of virtual functions?
Is the usage of std::any valid in this situation?
Is there a better way to implement such container?
Is there a way to force implementation as it is with virtual functions (by using virtual <type> foo() = 0)?
Is it a good idea to create an object that will be a CRTP handler? So I will not have a function for CRTP call, but an object, that can manage those calls?
Thank you.
Here is the base class:
class base {
private:
base() = default;
friend T;
T& implementation = static_cast<T&>(*this);
public:
auto do_stuff() {
return implementation.do_stuff();
}
};
Here is the implementation:
#include <iostream>
class implementation_a : public base<implementation_a> {
public:
auto do_stuff() {
std::cout << 42 << std::endl;
}
};
class implementation_b : public base<implementation_b> {
public:
auto do_stuff() {
return 420;
}
};
Here's the container:
#include <vector>
#include <any>
class crtp_vector {
private:
std::vector<std::any> vec;
public:
auto begin() {
return vec.begin();
}
auto end() {
return vec.end();
}
auto empty() {
return vec.empty();
}
auto size() {
return vec.size();
}
void clear() {
vec.clear();
}
void push_back(const std::any& val) {
vec.push_back(val);
}
auto emplace_back(const std::any& val) {
vec.emplace_back(val);
}
};
Here's the main:
#include "crtp_container.h"
#include <utility>
/* crtp call handler */
template <typename T>
auto crtp_call(T& val) {
return val.do_stuff();
}
int main() {
crtp_vector vec;
implementation_a A;
implementation_b B;
vec.push_back(A);
vec.push_back(B);
for(auto &member : vec) {
if(member.type().name() == typeid(implementation_a).name()) {
crtp_call(std::any_cast<implementation_a&>(member));
}
else if(member.type().name() == typeid(implementation_b).name()) {
std::cout << crtp_call(std::any_cast<implementation_b&>(member)) << std::endl;
}
else {
std::cerr << "no viable type conversion" << std::endl;
}
}
return 0;
}
You make it way too complicated. The code shown doesn't use base in any way; nothing would change if you simply remove it entirely. Even though you keep saying "CRTP", you aren't actually relying on CRTP for anything.
The code doesn't use the ability of std::any to hold any type; it's only used to hold one of a fixed set of types known at compile time. std::variant is better for this.
All told, the example boils down to this:
class implementation_a {
public:
auto do_stuff() {
std::cout << 42 << std::endl;
}
};
class implementation_b {
public:
auto do_stuff() {
std::cout << 420 << std::endl;
return 420;
}
};
int main() {
implementation_a A;
implementation_b B;
std::vector<std::variant<implementation_a, implementation_b>> vec;
vec.push_back(A);
vec.push_back(B);
for(auto &member : vec) {
std::visit([](auto& elem) { elem.do_stuff(); }, member);
}
return 0;
}
Demo
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();`
};
};
In many places in my code I need to construct understandable error messages, but creating string streams all the time is tedious, especially when you have to create a string in an constructor's initialisation list. If this could be done with a simple function it would make the code significantly more readable.
Given one of many example use cases below, what would be an elegant way of implementing the below createString function?
struct Base {
std::string msg;
Base(const std::string& msg) : msg(msg) { }
};
struct Derived: public Base {
Derived(int value)
// Parent constructor requires a string so we have to create it inline
: Base(createString("This is class " << value))
{ }
};
int main(void)
{
int i = 5; // some number obtained at runtime
Derived d(i);
std::cout << d.msg << "\n";
return 0;
}
So far I have come up with this C++11 version, but it suffers from a few drawbacks (requires preprocessor macro, sometimes strings have to be enclosed in std::string(), etc.) so I'm wondering whether anyone has come up with a better alternative?
#include <sstream>
#define createString(a) \
(static_cast<const std::ostringstream&>(std::ostringstream() << a).str())
Provide a wrapper around std::stringstream and have it be implicitly convertible to std::string. It changes the syntax a little bit:
class WrapSStream
{
public:
template <typename T>
WrapSStream& operator<<(const T& val)
{
ss << val;
return *this;
}
operator string(){return ss.str();}
private:
stringstream ss;
};
struct Base {
string msg;
Base(const string& msg) : msg(msg) { }
};
struct Derived: public Base {
Derived(int value)
// Parent constructor requires a string so we have to create it inline
: Base(WrapSStream() << "This is class " << value)
{ }
};
int main(void)
{
int i = 5; // some number obtained at runtime
Derived d(i);
cout << d.msg << "\n";
return 0;
}
Outputs This is class 5.
Live demo
I have a templated class Parameter which can (or must) be specialized.
I want to put all my parameters in a container.
How to do this if my parameters are instanciated with different types?
In the class Container, I would like to have a vector<Parameter*> from different types (int, double, ...) or something equivalent which seems to not possible.
If the Parameter class is derived from a base class, then The Container can declare the vect as vector<Base*>. But in this case, we can do nothing specific in Container::foo.
Below is my source example. One of my parameters is a QString which is not compatible with ostream.
Thanks for your comments.
#include <QString>
#include <vector>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
#define P(a) cout << #a << ":" << a << endl
/*
class Base {
};
*/
template<typename T> class Parameter /*: public Base */ {
private:
T val;
public:
void setVal(const T &val) {
this->val = val;
}
const T &getVal() {
return val;
}
string getFoo() {
stringstream s;
s << val;
return s.str();
}
};
template<>
string Parameter<QString>::getFoo() {
stringstream s;
s << val.toStdString();
return s.str();
}
class Container {
public:
void push_back(Parameter *base) {
vect.push_back(base);
}
void foo() {
/* do something with the parameters */
}
private:
vector<Parameter*> vect;
};
int main() {
Parameter<int> pi;
Parameter<QString> ps;
pi.setVal(10);
ps.setVal("QString");
P(pi.getVal());
P(ps.getVal().toStdString());
P(pi.getFoo());
P(ps.getFoo());
Container container;
container.push_back(&pi);
container.push_back(&ps);
}
Many thanks to you comments. I will follow your advice and use boost::any.
Here is the updated version :
#include <boost/any.hpp>
#include <QString>
#include <vector>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
#define P(a) cout << #a << ":" << a << endl
template<typename T> class Parameter {
private:
T val;
public:
void setVal(const T &val) {
this->val = val;
}
const T &getVal() {
return val;
}
string getFoo() {
stringstream s;
s << val;
return s.str();
}
};
template<>
string Parameter<QString>::getFoo() {
stringstream s;
s << val.toStdString();
return s.str();
}
class Container {
public:
void push_back(boost::any base) {
vect.push_back(base);
}
void foo() {
cout << "do something with the parameters\n";
for (vector<boost::any>::iterator i = vect.begin(); i != vect.end(); ++i) {
boost::any a = (*i);
if (a.type() == typeid(Parameter<int>*)) {
Parameter<int> *ai = boost::any_cast<Parameter<int> *>(a);
cout << ai->getFoo() << endl;
} else if (a.type() == typeid(Parameter<QString>*)) {
Parameter<QString> *aq = boost::any_cast<Parameter<QString> *>(a);
cout << aq->getFoo() << endl;
} else {
cout << "unknown type:" << a.type().name() << endl;
}
}
}
private:
vector<boost::any> vect;
};
int main() {
Parameter<int> pi;
Parameter<QString> ps;
pi.setVal(10);
ps.setVal("QString");
P(pi.getVal());
P(ps.getVal().toStdString());
P(pi.getFoo());
P(ps.getFoo());
Container container;
container.push_back(&pi);
container.push_back(&ps);
container.foo();
}
The correct solution is to write good enough interface for the Base class so that you can do everything you need to do:
class Base {
public:
virtual void *GetVal() const=0;
virtual void SetVal(void *ptr)=0;
virtual std::string Type() const=0;
virtual std::string GetAsString() const=0;
};
While this might not be what you want, it still allows passing values from one parameter to the next. Once you want the actual value, you do need to know the type on compile-time. Switch-case for the type might help with making it runtime.
You could use Boost.Any which can hold any type of data. You would then use boost::any_cast<> to convert the object back to the correct type.
Other than that, you'll have to go for the base class approach, but as you mentioned, it could be hard to then make Container::foo do anything useful.
One way you could solve this problem is to have all your foo functions take a string as a parameter, then each specific implementation of the function would parse that string and convert it to the correct type.
Edit: Boost.Any example:
#include <iostream>
#include <boost/any.hpp>
int main()
{
boost::any param = 89;
// This will fail because `param` is currently holding an int
// not a char
char ch = boost::any_cast<char>(param);
// This works
int i = boost::any_cast<int>(param);
// You can always change the value and type of what
// `param` is holding
param = "example";
}
Every thing inside a container has to be the same type. I have done something similar to your approach where I made a base class that had some useful generic interface and the derived class was templated. The only other way to approach a solution would involve defining a base class function to return a value to indicate the type and then downcasting the base.
It's hard to explain exactly what I want to do here, but I have a base class and two classes which inherit this base class. Both classes which inherit it have their own unique members. I want to be able to pass both to a method, and have that method detect which it is, then access their unique members. I can't assume there will only be two classes which inherit it, so i'm looking for something of a more general solution.
Here is an example of what I'd like to do:
#include <iostream>
class Base {
public:
int _type;
Base() { }
};
class First : public Base {
public:
int _first_only;
First() { }
};
class Second : public Base {
public:
int _second_only;
Second() { }
};
void test (Base b) {
std::cout << "Type: " << b._type << std::endl;
if(b._type==1) {
std::cout << "First\n";
// Want to be able to do this
std::cout << "Val: " << (First)b._first_only << std::endl;
} else if(b._type==2) {
std::cout << "Second\n";
// And this
std::cout << "Val: " << (Second)b._second_only << std::endl;
}
}
int main() {
First f;
f._first_only=1;
f._type=1;
Second s;
s._type=2;
s._second_only=2;
test(f);
test(s);
}
This is similar to others answers:
You can write polymorphic classes to get this behavior using virtual functions.
Pass the Dervied class objects either by pointer or by reference to get polymorphic behaviour. Otherwise it will lead to object slicing. Your test() function leads to object slicing.
This code may also help you. You can see that there are different ways to print the type. I used GetBaseType(), GetDerivedType() and GetType(). Among these GetType() method is convenient for you case. There are two constructors for convenience. Constructors allow to initialize data members.
class Base {
private:
int _type;
public:
Base(int type) : _type(type) { }
int GetBaseType() { return _type; }
virtual int GetDerivedType() = 0;
virtual int GetType() { return _type; }
};
class First : public Base {
private:
int _first_only;
public:
First() : Base(1), _first_only(1) { }
First(int first_only) : Base(first_only), _first_only(first_only) { }
int GetDerivedType() { return _first_only; }
virtual int GetType() { return _first_only; }
};
class Second : public Base {
private:
int _second_only;
public:
Second() : Base(2), _second_only(2) { }
Second(int second_only) : Base(second_only), _second_only(second_only) { }
int GetDerivedType() { return _second_only; }
virtual int GetType() { return _second_only; }
};
void test (Base &b) {
std::cout << "Type: " << b.GetBaseType() << std::endl;
std::cout << "Type: " << b.Base::GetType() << std::endl;
std::cout << "Dervied type: \n";
std::cout << "Val: " << b.GetDerivedType() << std::endl;
std::cout << "Val: " << b.GetType() << std::endl;
}
int main() {
First f(1);
Second s(2);
test(f);
test(s);
First f1;
Second s1;
test(f1);
test(s1);
}
Either declare a virtual function in Base
Move the common members types from First and Second into Base.
For your specific problem, 2nd option is better:
class Base {
public:
int _member; // have getter() method, if '_member' is private
Base() { }
};
Inside, test():
void test (Base &b) { // <--- practice to pass by reference if copy is not needed
// use b._member;
};
Your code does not work polymorphically, because you are passing the function-parameter by value, which results in slicing.
If you have a method that does different things for different types, consider overloading it for each of these types.
Three things I'd do:
In general switching on type codes is not considered good object oriented design: Instead pull the switched code into the classes.
I'd also set up the type tags in the constructor of the specific classes.
And as others have mentioned you need to pass the argument by reference to avoid slicing.
Here's what the code would look like:
#include <iostream>
class Base {
public:
int _type;
Base() { }
virtual void print_to_stream( std::ostream & os ) const =0;
};
class First : public Base {
public:
int _first_only;
First() { _type =1; }
void print_to_stream( std::ostream & os ) const
{
os<<"First\n";
os<<"Val: " << _first_only << std::endl;
}
};
class Second : public Base {
public:
int _second_only;
Second() { _type=2; }
void print_to_stream( std::ostream & os ) const
{
os << "Second\n";
os << "Val: " << _second_only << std::endl;
}
};
void test (Base & b)
{
std::cout << "Type: " << b._type << std::endl;
b.print_to_stream( std::cout );
}
int main() {
First f;
f._first_only=1;
Second s;
s._second_only=2;
test(f);
test(s);
}