C++ Virtual template method - c++

I have an abstract class (I know that it will not compile this way, but it's for comprehension of what I want to do) :
class AbstractComputation {
public:
template <class T> virtual void setData(std::string id, T data);
template <class T> virtual T getData(std::string id);
};
class Computation : public AbstractComputation {
public:
template <class T> void setData(std::string id, T data);
template <class T> T getData(std::string id, T data);
};
So when I call setData<double>("foodouble", data) I want the double identified by foodouble (internal mechanism which is not the main concern here) to be set to the double data.
So how to do that?
I think that there may be a mean by typing something like virtual void setData<double>(std::string id, double data) but I don't know how to do it.

The problem is that you cannot mix static time polymorphism (templates) with runtime polymorphism easily. The reason for the language disallowing the particular construct in your example is that there are potentially infinite different types that could be instantiating your template member function, and that in turn means that the compiler would have to generate code to dynamically dispatch those many types, which is infeasible.
There are different things that can be done here to get around the limitation, basically either take away the static or the dynamic polymorphism. Removing dynamic polymorphism from the equation could be done by providing a type that is not derived from, to store the <key,value> mappings, and then offering the template that resolves that only at the base level:
class AbstractComputation {
public:
template <typename T>
void setData( std::string const & id, T value ) {
m_store.setData( id, value );
}
template <typename T>
T getData( std::string const & id ) const {
return m_store.getData<T>( id );
}
protected:
ValueStore m_store;
};
Now deriving classes can access the ValueStore from the base and there is no need for polymorphism. (This can also be done by implementing the functionality directly in AbstractComputation but it probably makes sense to separate concerns)
The other option is to maintain runtime polymorphism, but remove static polymorphism. This can be done by performing type erasure on the base class and then dispatching to the appropriate (non-templated) function that takes the type-erased arguments. The simplest version of this is just using boost::any:
class AbstractComputation {
public:
template <typename T>
void setData( std::string const & id, T value ) {
setDataImpl( id, boost::any( value ) );
}
template <typename T>
T getData( std::string const & id ) const {
boost::any res = getDataImpl( id );
return boost::any_cast<T>( res );
}
protected:
virtual void setDataImpl( std::string const & id, boost::any const & value ) = 0;
virtual boost::any getDataImpl( std::string const & id ) const = 0;
};
How type erasure is implemented under the hood is interesting, but out of the scope here, the important part is that a boost::any is a concrete (non-templated) type that can store any type internally by using type erasure on the arguments, and at the same time allows for type-safe retrieval of the data.

In some cases it may be enough to move the templating from method level to class level, e.g.:
#include <iostream>
template<typename T>
class AbstractComputation {
public:
virtual void setData(std::string id, T data)
{
std::cout << "base" << std::endl;
}
};
template<typename T>
class Computation : public AbstractComputation<T> {
public:
virtual void setData(std::string id, T data)
{
std::cout << "derived" << std::endl;
}
};
int main()
{
AbstractComputation<int> *x = new Computation<int>();
x->setData("1", -1);
delete x;
return 0;
}

You can probably use boost::any in your case.
virtual void setData(std::string id, boost::any data);
It is a wrapper that can encapsulate almost anything.
More info on a similar topic in this answer.

First, you cannot have virtual template functions. As templates are resolved at compile time, virtual will not work, as the compiler would not know which template to pick. See here, for more info about this.

If you know list of possible types in advance, preprocessor may help:
#define MY_CLASSES MYTYPE(int) MYTYPE(float) MYTYPE(double)
class AbstractComputation {
public:
# define MYTYPE(T) virtual void setData(std::string id, T data)=0;\
virtual void getData(std::string id, T& dst_data)=0;
MY_CLASSES
# undef MYTYPE
};
class Computation : public AbstractComputation {
public:
# define MYTYPE(T) virtual void setData(std::string id, T data){std::cout<<"writing: "<<data<<std::endl;}\
virtual void getData(std::string id, T& dst_data){dst_data=0;/*put your actual implementation here*/}
MY_CLASSES
# undef MYTYPE
};
If you don't know a complete list of possible types, perhaps, your problem is unresolvable. Type erasure, as mentioned by others, may also help.. but not in all circumstances.

Use boost::any to accept the datum, and then when you actually set, grab the correct type from it.

Related

CRTP and method returning void *

I use C++ 11. I have a Base class and several derived classes for parsing different configuration files line by line.
template <class T>
class Base
{
public:
virtual ~Base();
bool load_from_file(const QString& str);
virtual void* get_data(const QString& str) const = 0;
private:
QList<QSharedPointer<T> > items_;
};
Each descendant (class Derived: public Base<My_struct>) must provide get_data() implementation.
Each My_struct instance contains information from certain line of a settings file.
For example, imagine a typical file with a list of proxies.
My_struct instances are wrapped in smart pointers in Base class in the load_from_file() method and appended to the items_ member. load_from_file() method casts void* to T* before wrapping.
Is it possible to redesign these classes in order to avoid using void* (and without libraries like boost::any)?
I mean considering CRTP and so on. Usually CRTP examples contain methods of derived classes with void return values (like procedures in Pascal).
Bro! Try to switch to C++14 and use the following snippet as a hint:
template <typename Derived>
struct base
{
template <typename T>
auto f(T x)
{
return static_cast<Derived&>(*this).f_impl(x);
}
auto g()
{
return static_cast<Derived&>(*this).g_impl();
}
};
struct derived : base<derived>
{
bool f_impl(int x)
{
return true;
}
double g_impl()
{
return 4.2;
}
};
This fragment has been taken from here.

Named/typed parameters using variadic templates

I'm playing around a bit with named/typed parameters using variadic templates, and have the following class:
class audio_source_t
{
public:
virtual ~audio_source_t()
{
}
template<typename T...>
void receive(const T&... args)
{
auto tuple = std::tie(args...);
receive_impl(std::get<boost::optional<sample_rate_t>>(tuple),
std::get<boost::optional<nb_channels_t>>(tuple));
}
private:
virtual void receive(audio_frame_t& destination,
const boost::optional<sample_rate_t>& sample_rate_hint = nullptr,
const boost::optional<nb_channels_t>& nb_channels_hint = nullptr) const;
};
Where the parameters types are defined as:
template<typename T>
class explicit_class
{
public:
explicit sample_rate_t(T value)
: value_(value)
{
}
explicit operator T()
{
return value_;
}
private:
T value_;
};
class sample_rate_t : public explicit_class<int>{};
class nb_channels_t : public explicit_class<int>{};
So far so good, now I can use the class as follows:
audio_source.receive(boost::optional<sample_rate_t>(48000),
boost::optional<nb_channels_t >(2));
audio_source.receive(boost::optional<nb_channels_t>(2),
boost::optional<sample_rate_t>(48000));
Parameter order doesn't matter and it is explicit, great.
However, it would be even better if optional parameters, were actually optional and I wouldn't need to mention boost::optional for specified parameters, e.g.
audio_source.receive(sample_rate_t(48000),
nb_channels_t(2));
audio_source.receive(nb_channels_t(2),
sample_rate_t(48000));
audio_source.receive(sample_rate_t(48000));
audio_source.receive(nb_channels_t(2));
I know that I could just simply create all the possible overloads, however when I get up to +3 parameters, that quickly turn impractical.
Any suggestions as to how to achieve this improvement?
Basically what I need is something like:
get_or_nullptr_t<sample_rate_t>(tuple)
Which during compile time can decide whether the tuple contains the type and otherwise return std::nullptr_t().

How can I have a container of template elements

I am trying to have a container of template elements but it's not compiling because the first argument is not given
So I want to put the following class in a std::map
template <typename T>
class TemplateParam
{
ITemplateParam<T> param_;
public:
TemplateParam(T value)
{
if (sizeof(value) >= sizeof(void*))
param_ = ptrTemplateParam<T>(value);
else
param_ = cpyTemplateParam<T>(value);
}
const T &getParam() const { return param_.getParam(); }
};
ITemplateParam
template <typename U>
class ITemplateParam
{
public:
virtual ~ITemplateParam(){}
virtual const U& getParam() const = 0;
};
I think I understand why I can't put elements of different sizes in a container, it's why I used ptrTemplateParam and cpyTemplateParam. (I have also tried with the shared_ptr)
Do you have any idea how can I resolve my problem
I can use boost library
I have looked at this link but I don't know how can I declare the getter.
Edit:
Thanks to your answer I am able to store it in a map but I'm not able to insert an element in the map and I have to use void*
So I have changed my class to:
class ITemplateParam
{
public:
virtual ~ITemplateParam(){}
virtual const void *getParam() const = 0;
};
template <typename U>
class ptrTemplateParam : public ITemplateParam
{
U param_;
public:
ptrTemplateParam(U & param) : param_(param) {}
virtual const void *getParam() const { return param_; }
};
class TemplateParam
{
std::shared_ptr<ITemplateParam> param_;
public:
template <typename T>
TemplateParam(T value): param_(ptrTemplateParam<T>(value))
{
}
const void *getParam() const { return param_->getParam();}
};
and I try to do
std::map<std::string, TemplateParam> m_;
m_["integer"] = TemplateParam(5);
Edit2
boost::any was the solution
If you need to have a container that contains elements of different type then you have
basically 3 ways:
Have container of variants or unions.
Have container of polymorphic pointers or polymorphic smart pointers.
Use intrusive container.
It is unclear from your question what would be best for you.
IMHO, if you want to put different items in the same container, you should consider using Boost.Variant. This is not a direct answer to your actual example here, but I found this pattern very useful for this category of problems. You avoid using pointers and enforcing inheritance in an elegant way.
class A {};
class B {};
typedef boost::variant<A, B> item_t;
...
vector<item_t> my_container;

Efficient way to define an introspective C++ class hierararchy description ?

I have a C++ class hierarchy defined by inheritance and I store a description of this hierarchy in it that I can later use for introspection. I would like to know if there is a more efficient or cleaner way to define this than the way I currently do it.
Here is a stripped down version of my code
// in header file (hpp)
struct Type
{
Type( const string& n, const Type* p = nullptr ) : name(n), parent(p) {}
const string name;
const Type* parent;
};
class Base
{
public:
static const Type m_type;
virtual const Type& type() const { return m_type; }
};
class Derived : public Base
{
public:
static const Type m_type;
const Type& type() const { return m_type; }
};
// in implementation file (cpp)
const Type Base::m_type( "Base" );
const Type Derived::m_type( "Derived", &Base::m_type );
Not necessarily more efficient but think whether you actually want to require a common base class. An alternative approach uses a global type information registry. Then querying a type’s type information is done via TypeInfo::get(my_variable) or TypeInfo::get(typeid(my_type)).
This has the advantage that it also works with existing types, which just need to be added to this type info registry.
Internally, the registry would use a map from std::type_info to Type or similar. The following is a proof of concept. Unfortunately the code doesn’t compile on either clang or GCC. Based on the error messages, I’m suspecting a bug but I could also be wrong …
struct Type {
std::string name;
std::vector<Type*> parents;
// TODO Extend by fully-qualified name (namespace) etc.
template <typename... T>
Type(std::string&& name, T*... parents)
: name(name), parents{parents...} { }
};
struct TypeInfo {
template <typename T>
static Type const& get(T const&) { return get(typeid(T)); }
template <typename T>
static Type const& get() { return get(typeid(T)); }
static Type const& get(std::type_info const& info) {
auto i = types.find(info);
if (i == types.end())
throw unknown_type_error(info.name());
return i->second;
}
template <typename T>
static void register_type(Type&& type) {
types.insert(std::make_pair(typeid(T), type));
}
typedef std::unordered_map<std::type_info, Type> type_dir_t;
static type_dir_t types;
};
Full code available as gist on github.
Having a common base class for logically unrelated classes is generally frowned upon in C++, although it could be argued that this is similar to CRTP / mixins, in which common base classes are encouraged. So I’d say that there isn’t necessarily anything wrong with the approach if you don’t care for existing types.

C++ visitor pattern handling templated string types?

I'm trying to use the visitor pattern to serialize the contents of objects. However one snag I'm hitting is when I'm visiting strings. My strings are of a templated type, similar to STL's basic_string. So something like:
basic_string<char_type, memory_allocator, other_possible_stuff> \\ many variations possible!
Since I can have very many different templated string types, I can't go and add them to my visitor interface. It would be ridiculous. But I can't add templates to my VisitString method because C++ prevents using templates parameters in virtual methods.
So what are my options to work around this?
EDIT: I've added some basic code
class IVisitor
{
public:
virtual void VisitString(some_kind_of_string_type string) = 0; // this is what I want in theory
};
class MyObject
{
public:
typedef basic_string<char8, myAllocator, some_flag> MyStringType;
Accept(IVisitor* visitor)
{
visitor->VisitString(mString);
}
private:
MyStringType string;
};
class MyOtherObject
{
public:
typedef basic_string<char16, myOtherAllocator, some_other_flag> MyOtherStringType;
Accept(IVisitor* visitor)
{
visitor->VisitString(mString);
}
private:
MyOtherStringType string;
};
class Reader : public IVisitor
{
public:
virtual void VisitString(some_kind_of_string_type string)
{
// read some data, give it to the string
}
}
Do you need runtime polymorphism?
struct object {
template <typename Visitor>
void accept( Visitor & v )
{
v( x );
v( a );
}
int x;
std::string a;
};
struct complex_object {
template <typename Visitor>
void accept( Visitor & v ) {
v( i );
o.accept(v); // [1]
}
int i;
object1 o;
};
struct DumpScreenVisitor {
void operator()( int x ) { std::cout << x << std::endl; }
template <typename char_t, typename traits_t, typename alloc_t>
void operator()( std::basic_string<char_t, traits_t, alloc_t> const & str )
{
std::cout << str << std::endl;
}
};
The call in [1] can be converted into v( o ) with a generic templated operator() in the visitors that is the least specialized:
template <typename O>
void DumpScreenVisitor::operator()( O & o )
{
o.accept( *this );
}
But this can interfece with other visitor implementations (for example, the above visitor can be implemented with a single templated method):
struct DumpScreenVisitor {
template <typename T>
void operator()( T const & t ) {
std::cout << t << std::endl;
}
};
So at the end you will have to compromise in either way.
This approach is similar to the boost::variant visitor implementation (you may want to take a look at it), with the difference that the boost::variant is a single class and not a hierarchy.
In the end, I went with a slightly different approach. Instead of hoping to use a visitor with templated methods (which is, of course, impossible), I decided to pass a visitor-like class as a template parameter to my object's visit method. Totally simplified example:
class SomeKindOfVisitor // doesn't need to derive from a base class.
{
template <class StringClass>
void VisitString(StringClass& string) // I get to keep templated methods
}
class MyObject
{
typedef basic_string<char8, myAllocator, some_flag> MyStringType;
public:
template <class VisitorClass>
void Accept(VisitorClass& visitor)
{
vistior.VisitString<MyStringType>(mMyString);
}
private:
MyStringType mMyString;
}
With this method, I still get to use my templated strings while still being able to pass any kind of "visitor" to my objects.
your visitor should handle only a basic representation of strings (char* / wchar*);
it is then up to the accept method to process the cast.
Well, the question is, of the template parameters on your string can be so different, can you apply one single serialization method for them? If so, you could write an adapter that has a templated constructor that extracts all the information needed for serialization into a uniform representation. Then you visit the serializer with the adapter.
EDIT: After you added you code, I still think that an adapter could solve your problem, only the other way around. In you Accept-method, construct a local adapter and pass it to the Visitor. When the Visitor has modified it, you can use a template method extractToString on the adapter that converts the information to a specific string version. This may make the adapter quit complex, depending on how different the string-template instantiations have to be handled.
Since all your string classes are of different types, you will need some level of compromise (either a common sub-type, with virtual methods, for your strings, or an adapter, or adding a method for each different type to the visitor). Mixing generic-programming and oo can be a pain, especially if you don't accept compromises.
Eg.
class string_tag { /* common visitor interface */ };
template<typename char_t, ...> class basic_string : public string_tag {};
class IVisitor
{
public:
virtual void VisitString(string_tag& string) = 0; // this is what I want in theory
};
class MyObject
{
public:
typedef basic_string<char8, myAllocator, some_flag> MyStringType;
Accept(IVisitor* visitor)
{
visitor->VisitString(string);
}
private:
MyStringType string;
};
class MyOtherObject
{
public:
typedef basic_string<char16, myOtherAllocator, some_other_flag> MyOtherStringType;
Accept(IVisitor* visitor)
{
visitor->VisitString(string);
}
private:
MyOtherStringType string;
};
class Reader : public IVisitor
{
public:
virtual void VisitString(string_tag& string)
{
// read some data, give it to the string
}
}
May be you can consider below, but in this case you need to separate visitor mechanisms to different visitor classes. WStringVisitor and StringVisitor are just examples for different Visitor semantics.
#include <string>
#include <iostream>
using namespace std;
template <typename stringType>
class IVisitor{
public:
virtual void visit(stringType _string)=0;
};
class StringVisitor: public IVisitor<string>{
public:
void visit(string str){
cout<<"This is std::string implementation: "<< str << endl;
}
};
class WStringVisitor: public IVisitor<basic_string<wchar_t>>{
public:
void visit(basic_string<wchar_t> str){
//wprintf(L"This wide implementation : %S", str.c_str());
wcout<<"This is WString Visitor: "<< str << endl;
}
};
class MyObject{
public:
typedef basic_string<char> MyStringType;
void accept(IVisitor<MyStringType>& visitor){
visitor.visit("TEST STRING");
}
};
class MyOtherObject
{
public:
typedef basic_string<wchar_t> MyOtherStringType;
void accept(IVisitor<MyOtherStringType>& visitor)
{
visitor.visit(L"TEST WSTRING");
}
};
int _tmain(int argc, _TCHAR* argv[])
{
MyObject acceptor;
MyOtherObject otheracceptor;
StringVisitor visitor;
WStringVisitor wvisitor;
acceptor.accept(visitor);
//otheracceptor.accept(visitor); compile error
otheracceptor.accept(wvisitor);
return 0;
}
I think the fundamental problem here is that the Visitor pattern is all about virtual functions, while you herd your strings through function templates. And these just don't easily mix. In fact, the only way I can think of to mix the two is type erasure.
If you don't find a way to do what you want using this technique, I don't think you'll find a way.