This makes no sense to me. GCC is complaining that the call below in main() to processMsg() is ambiguous, even though all of the template-created processMsg() calls are reported back as candidates. I've tried implementing this variadic template prototype three different ways and they all lead back to this same issue of ambiguous request. I did get closer when I broke the template implementation up into different cases for and but then I could the compiler could only resolve the first lookup in the tuple.
I've pasted a small example. I'm sure I'm missing something simple....
#include <tuple>
//----------------------------------------------------------------------
//
class MessageBase
{
public:
MessageBase( const int _id ) : m_id( _id ) {}
virtual int getMessageID() const { return( m_id ); }
private:
const int m_id;
};
#define MESSAGE( NAME, VAL ) \
class Message##NAME : public MessageBase { \
public: \
Message##NAME() : MessageBase( VAL ) { } \
};
MESSAGE( One, 1 );
MESSAGE( Two, 2 );
MESSAGE( Ten, 10 );
//----------------------------------------------------------------------
//
template< typename T >
struct MyMessageInterface {
virtual void processMsg( const T& t ) { }
};
template< typename... T >
struct MyMessageHandler : public MyMessageInterface< T >...
{};
template< typename... T >
struct MyMessageHandler< std::tuple< T... > >
: public MyMessageInterface< T >...
{};
//----------------------------------------------------------------------
//
typedef std::tuple< MessageOne, MessageTwo, MessageTen > Foople;
int main()
{
MyMessageHandler< Foople > mmh;
mmh.processMsg( MessageOne() );
}
You could add a forwarder to the specialization of MyMessageHandler:
template< typename... T >
struct MyMessageHandler< std::tuple< T... > >
: public MyMessageInterface< T >...
{
template< typename U >
void processMsg( const U& u )
{
MyMessageInterface< U >::processMsg( u );
}
};
Live example
The reason you need to do something like this (or what Jarod42 proposed) is that the virtual methods of the base classes are not visible from the derived class when the name is ambiguous. Normally you'd add a using declaration to pull in what you need, but in your case a forwarder might be easier.
You may rewrite MyMessageHandler as follow: Live example
template <typename... Ts> struct MyMessageHandler;
template <typename T> struct MyMessageHandler<T>
{
virtual void processMsg(const T&) { }
};
template <typename T, typename...Ts>
struct MyMessageHandler<T, Ts...> : MyMessageHandler<T>, MyMessageHandler<Ts...>
{
using MyMessageHandler<T>::processMsg;
using MyMessageHandler<Ts...>::processMsg;
};
template <typename... Ts>
struct MyMessageHandler<std::tuple<Ts...>> : public MyMessageHandler<Ts...>
{
};
You have to (unfortunately) explicitly disambiguate the base class that you want to call:
int main()
{
MyMessageHandler< Foople > mmh;
mmh.MyMessageInterface<MessageOne>::processMsg( MessageOne() );
return 0;
}
You can bury the cast in another template if you like:
template <typename Handler, typename Message>
void caller(Handler &h, const Message &m)
{
h.MyMessageInterface<Message>::processMsg( m );
}
int main()
{
MyMessageHandler< Foople > mmh;
caller(mmh, MessageOne());
return 0;
}
The problem is that member look-up is ambiguous because all of the MyMessageInterface<T>s are a direct base class of MyMessageHandler.
We need to pull in the set of names into MyMessageHandler itself so that we can form the overload set with those names.
First approach might be to do something like: using TMessageInterface<T>::processMsg;... but of course that's not legal.
My suggestion would be to either do what #Jarod42 did to recursively pull in the processMsg functions, or you can do:
template <typename... Ts>
struct MyMessageHandler : MyMessageInterface<Ts>... {
template <typename Msg>
void processMsg(const Msg &msg) {
MyMessageInterface<Msg>::processMsg(msg);
}
};
which invokes the specific base class' processMsg.
Related
Consider the following example:
template <typename Consumer>
class ClassA
{
public:
template<class... Args>
explicit ClassA(Args &&... args) :
consumer_(std::forward<Args>(args)...)
{
}
void consume()
{
consumer_.consume();
}
private:
Consumer consumer_;
};
template <typename Consumer>
class ClassB
{
public:
template<class... Args>
explicit ClassB(Args &&... args) :
consumer_(std::forward<Args>(args)...)
{
}
void consume()
{
consumer_.consume();
}
private:
Consumer consumer_;
};
class ClassC
{
public:
explicit ClassC(int val) :
val_(val)
{
}
void consume()
{
std::cout << "ok " << val_ << std::endl;
}
private:
int val_;
};
void usage()
{
ClassA<ClassB<ClassC>> composed_object(3);
composed_object.consume();
}
It's a kind of templated bridge (or proxy? or strategy?) pattern, that I can easily compose and change implementation in compile time.
I try to avoid using of dynamic polymorphism due to performance reasons.
So, the question: How to allow ClassB to call some of ClassA methods?
The first thing that comes to my mind is to pass a reference of ClassA to ClassB. But there is a templated class chain and I don't want to change class chain usage.
I can rewrite ClassB as follows:
template <typename Interface, typename Consumer>
class ClassB
{
public:
template<class... Args>
explicit ClassB(Interface &interface, Args &&... args) :
consumer_(std::forward<Args>(args)...),
interface_(interface)
{
}
void consume()
{
consumer_.consume();
}
private:
Consumer consumer_;
Interface &interface_;
};
So, it now takes an additional templated param of parent class Interface and a reference to parent in constructor.
But I have no idea how to specify templated param Interface in ClassA without change the chain usage.
To my mind it's a kind of template param infinity loop.
You want to pass the producer to ClassB without passing it. We can do this via the CRTP.
template <typename Consumer>
class ClassA:private Consumer
{
public:
template<class... Args>
explicit ClassA(Args &&... args) :
Consumer(std::forward<Args>(args)...)
{
}
void say_hello() { std::cout << "hello!\n"; }
void consume()
{
Consumer::consume();
}
};
and change ClassB similarly. Everything continues to work as is. Now you want ClassB to find its producer.
template <template<class>class Producer, typename Consumer>
class ClassB:private Consumer
{
public:
template<class... Args>
explicit ClassB(Args &&... args) :
Consumer(std::forward<Args>(args)...)
{
}
void consume()
{
GetProducer().say_hello();
Consumer::consume();
}
private:
Producer<ClassB>& GetProducer() { return *static_cast<Producer<ClassB>*>(this); }
Producer<ClassB> const& GetProducer() const { return *static_cast<Producer<ClassB> const*>(this); }
};
here we tell ClassB who produces for it, and add a private method that gets their producer (assuming their producer uses the same inheritance composition strategy).
void usage()
{
ClassA<ClassB<ClassA, ClassC>> composed_object(3);
composed_object.consume();
}
here we pass in to ClassB how they are in turn going to be produced.
A constructed class knows a few things. It knows its arguments to construction, and it also has an implicit this pointer.
Here we slip-stream the producer identity via CRTP and inheritance into the class, without having to pass it as an argument.
Using template aliases, you can even "skip" levels. If you get it wrong, however, UB quickly results.
A more meta approach can also be done.
template<template<class...>class Z, class...Us>
struct ztemplate {
template<class...Ts>
using result=Z<Us..., Ts...>;
};
template<class...> struct empty_t {};
template<class zProducer, class zConsumer, class...Ts>
class ClassA:
public zConsumer::template result< ztemplate<ClassA, zProducer>, Ts...>
{
public:
using Consumer = typename zConsumer::template result< ztemplate<ClassA, zProducer>, Ts... >;
using Producer = typename zProducer::template result< ztemplate<ClassA>, zConsumer, Ts... >;
template<class... Args>
explicit ClassA(Args &&... args) :
Consumer(std::forward<Args>(args)...)
{
}
void say_hello() { std::cout << "hello!\n"; }
void consume()
{
static_assert( std::is_same_v< typename Consumer::Producer, ClassA > );
Consumer::consume();
}
};
template <class zProducer, class zConsumer, class...Ts>
class ClassB:
public zConsumer::template result< ztemplate<ClassB, zProducer>, Ts...>
{
public:
using Consumer = typename zConsumer::template result< ztemplate<ClassB, zProducer>, Ts... >;
using Producer = typename zProducer::template result< ztemplate<ClassB>, zConsumer, Ts... >;
template<class... Args>
explicit ClassB(Args &&... args) :
Consumer(std::forward<Args>(args)...)
{
}
void consume()
{
static_assert( std::is_same_v< typename Producer::Consumer, ClassB > );
GetProducer().say_hello();
Consumer::consume();
}
private:
Producer& GetProducer() { return *static_cast<Producer*>(this); }
Producer const& GetProducer() const { return *static_cast<Producer const*>(this); }
};
template<class...>
class ClassC
{
public:
explicit ClassC(int val) :
val_(val)
{
}
void consume()
{
std::cout << "ok " << val_ << std::endl;
}
private:
int val_;
};
void usage()
{
ClassA<ztemplate<empty_t>, ztemplate<ClassB>, ztemplate<ClassC>> composed_object(3);
composed_object.consume();
}
but that probably goes too far.
Here every class in the chain is told about the structure of the entire chain "automatically". (the static asserts are not universal, just debug checks that things work in this specific instance by not-UB).
To reduce compile time bloat, you can change the passed in ClassC as follows:
template<class Z> struct zAlways {
template<class...>using result = Z;
};
void usage()
{
ClassA<zAlways<empty_t>, ztemplate<ClassB>, zAlways<ClassC>> composed_object(3);
composed_object.consume();
}
while removing template<class... from ClassC.
ztemplate is a pattern to pass a template as a class. We use it here because you cannot write a template that takes as its first argument a template that takes as its first argument a template that takes as its first argument a template that...
zAlways obeys the pattern, that the real template is in Foo::template result. Here we create a ztemplate that always returns a specific class.
But I digress.
I'm working with the following (simplified) factory design to create objects of some inheritance hierarchy, shouldn't be anything special:
// class to create
class Class
{
public:
Class(Type type, Foo foo);
};
// Simple creator class.
// Used in practice to do some runtime checks about whether or not construction is allowed.
class Creator
{
public:
Class* create( Type type, Foo foo ) const
{
return new Class( type, foo );
}
};
class Factory
{
public:
Factory
{
// fill object creator map on construction
_map[ "name" ] = new Creator<Class>;
}
Class* create( const std::string& name, Type type, Foo foo )
{
// fowards to map entry
return _map[name]->create( type, foo );
}
private:
std::map<std::string, Creator*> _map;
}
// client code
int main()
{
Factory f;
factory.create(name, type, foo);
}
Now I run into problems once I want to create subclasses which have a different constructor signature because the factory imposes a fixed signature on the entire inheritance hierarchy. I.e. for the following class I have no way of specifying the new 3rd parameter via the factory construction without imposing this extended signature on all other class of my hierarchy again.
class ExtClass : public Class
{
public:
Class(Type type, Foo foo, NewMember nm)
: Class(type, foo),
_nm(nm)
private:
NewMember _nm;
};
Is there a way to make this work with my current design without making pricinpal changes? I'm thinking of using templates or bind objects to make varying argument calls possible.
Or would you in this case suggest a different solution than the factory design?
This answer is different enough to my first solution and it includes what you might consider "principal changes" that I have made it a separate answer:
In my opinion, it is superior to my earlier solution, but it depends what your exact requirements are. The features here are:
Creator id is unique.
CreateObject supports implicit conversion of parameters.
The same limitation that the constructors must take const& parameters exists. It might not matter, but this solution only requires C++11. It would, of course, be a bit simpler with the new C++17 tuple features.
#include <boost/functional/factory.hpp>
#include <boost/function.hpp>
#include <boost/variant.hpp>
#include <map>
#include <stdexcept>
#include <tuple>
#include <type_traits>
#include <utility>
// Just for debugging.
#include <iostream>
#include <typeinfo>
#include <cxxabi.h>
// Tuple manipulation.
template <typename Signature>
struct signature_impl;
template <typename ReturnType, typename... Args>
struct signature_impl<ReturnType(Args...)>
{
using return_type = ReturnType;
using param_types = std::tuple<Args...>;
};
template <typename T>
using signature_t = signature_impl<T>;
template <std::size_t... Ints>
struct indices {};
template <std::size_t N, std::size_t... Ints>
struct build_indices : build_indices<N-1, N-1, Ints...> {};
template <std::size_t... Ints>
struct build_indices<0, Ints...> : indices<Ints...> {};
template <typename Tuple>
using make_tuple_indices = build_indices<std::tuple_size<typename std::remove_reference<Tuple>::type>::value>;
// The multiple-signature factory.
template <class AbstractProduct, typename IdentifierType, typename... ProductCreators>
class multifactory
{
using functions = boost::variant<boost::function<ProductCreators>...>;
std::map<IdentifierType, functions> associations_;
template <typename Signature>
struct dispatch_foo
{
template <typename CreateArgs, std::size_t... Indices>
typename std::enable_if<std::is_convertible<CreateArgs, typename signature_t<Signature>::param_types>::value, AbstractProduct>::type
static apply(boost::function<Signature> const &f, CreateArgs && t, indices<Indices...>)
{
return f(std::get<Indices>(std::forward<CreateArgs>(t))...);
}
template <typename CreateArgs, std::size_t... Indices>
typename std::enable_if<!std::is_convertible<CreateArgs, typename signature_t<Signature>::param_types>::value, AbstractProduct>::type
static apply(boost::function<Signature> const &, CreateArgs &&, indices<Indices...>)
{
return nullptr;
}
};
template <typename... CreateArguments>
struct dispatcher : boost::static_visitor<AbstractProduct>
{
std::tuple<CreateArguments...> args;
dispatcher(CreateArguments const&... args) : args{std::forward_as_tuple(args...)} {}
template <typename Signature>
AbstractProduct operator()(boost::function<Signature> const &f) const
{
int status;
std::cout << "visitor: " << abi::__cxa_demangle(typeid(Signature).name(), nullptr, 0, &status) << "\n";
return dispatch_foo<Signature>::apply(f, args, make_tuple_indices<std::tuple<CreateArguments...>>{});
}
};
public:
template <typename ProductCreator>
bool Register(IdentifierType id, ProductCreator &&creator) {
return associations_.emplace(id, std::forward<ProductCreator>(creator)).second;
}
bool Unregister(const IdentifierType& id) {
return associations_.erase(id) == 1;
}
template <typename... Arguments>
AbstractProduct CreateObject(const IdentifierType& id, Arguments const& ... args) {
auto i = associations_.find(id);
if (i != associations_.end()) {
dispatcher<Arguments...> impl(args...);
return boost::apply_visitor(impl, i->second);
}
throw std::runtime_error("Creator not found.");
}
};
struct Arity {
virtual ~Arity() = default;
};
struct Nullary : Arity {};
struct Unary : Arity {
Unary() {} // Also has nullary ctor.
Unary(int) {}
};
int main(void)
{
multifactory<Arity*, int, Arity*(), Arity*(const int&)> factory;
factory.Register(0, boost::function<Arity*()>( boost::factory<Nullary*>() ));
factory.Register(1, boost::function<Arity*(const int&)>(boost::factory<Unary*>()) );
auto a = factory.CreateObject(0);
assert(a);
assert(typeid(*a) == typeid(Nullary));
auto b = factory.CreateObject(1, 2);
assert(b);
assert(typeid(*b) == typeid(Unary));
}
Apologies for the different naming conventions, but this is the C++14 solution that I currently use. The two main shortcomings are
when calling CreateObject, the type of the value passed as an
argument must be the same as the type registered. You can't pass in
a float and call a constructor registered with a double
signature.
Due to an implementation detail in boost::bind,
parameters must be const &.
A design limitation because I wanted to use boost::factory is that objects of that class must be wrapped in a boost::function (to disambiguate the function signature).
So it works but it could definitely be improved with more metaprogramming wisdom:
#include <boost/functional/factory.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <cassert>
#include <map>
#include <tuple>
#include <type_traits>
#include <utility>
template <class AbstractProduct, typename IdentifierType, typename... ProductCreators>
class Factory
{
using AssociativeContainers = std::tuple<std::map<IdentifierType, boost::function<ProductCreators>>...>;
public:
template <typename Product, typename... Arguments>
bool Register(const IdentifierType& id, boost::function<Product(Arguments...)> creator) {
auto &foo = std::get<std::map<IdentifierType, boost::function<AbstractProduct(const Arguments&...)>>>(associations_);
return foo.emplace(id, creator).second;
}
// This function left as an exercise to the reader...
bool Unregister(const IdentifierType& id) {
return associations_.erase(id) == 1;
}
template <typename... Arguments>
AbstractProduct CreateObject(const IdentifierType& id, Arguments&& ... args) const {
auto const &foo = std::get<std::map<IdentifierType, boost::function<AbstractProduct(const Arguments&...)>>>(associations_);
auto const i = foo.find(id);
if (i != foo.end()) {
return (i->second)(std::forward<Arguments...>(args)...);
}
throw std::runtime_error("Creator not found.");
}
private:
AssociativeContainers associations_;
};
struct Arity {
virtual ~Arity() = default;
};
struct Nullary : Arity {};
struct Unary : Arity {
Unary() {}
Unary(double x) : x(x) {}
double x;
};
int main(void)
{
Factory<Arity*, int, Arity*(), Arity*(const double&)> factory;
factory.Register(0, boost::function<Arity*()>{boost::factory<Nullary*>()} );
factory.Register(1, boost::function<Arity*(const double&)>{boost::bind(boost::factory<Unary*>(), _1)});
auto x = factory.CreateObject(1, 2.0);
assert(typeid(*x) == typeid(Unary));
x = factory.CreateObject(0);
assert(typeid(*x) == typeid(Nullary));
}
Context
I'm currently working on my own library for loading custom script inside c++ applications.
Here's some sample code for explaining what it's doing:
script part:
test.ctv
script
{
object player = access("player");
player.posX = 1 + 2;
access("map").load("map.txt");
}
C++ part:
test.cpp
class Player : public Loadable{
private:
friend class cTVScript::scriptExecutor;
primaryLoadable<int> posX;
stringLoadable name;
public:
Player() : Loadable(&posX, "posX", &name, "name");
}
class Map : public Loadable{
private:
friend class cTVScript::scriptExecutor;
std::string mapName;
public:
void load(std::string map) {
mapName = map;
}
Map() : Loadable(&load, "load") {}
}
int main() {
Player *p = new Player();
Map *m = new Map();
cTVScript::LoadScript("test.ctv");
cTVScript::AddObject(p, "player");
cTVScript::AddObject(m, "map");
std::cout << player.posX.get() << std::endl; // for example purpose we just assume that posX are public
std::cout << player.mapName.get() << std::endl; // same for mapName
}
Problem
Variable accessing and using by the cTVScript::scriptExecutor is quite simple,
but my main problem is elsewhere:
How, in c++, can I save and call method/functions with differents prototype?
Some trick with the compiler could make it easier? (like knowing the type and numbers of arguments?)
Current Work-Around
Make the user define a sub-fonction like AccessibleLoad:
class Map{
[...]
public:
void load(std::string map) {
mapName = map;
}
static void AccessibleLoad(cTVScript::CallingPack& pack) {
/* arguments */
std::string map;
pack.loadArguments(map); // here the user ask for each arguments
/*calling object */
Map* _this;
pack.loadCallingObject(_this); // and here he ask for the calling object
_this->load(map);
}
Map() : Loadable(&AccessibleLoad, "load") {}
}
So!
Is there a trick or some way i could make it more easy for using functions/methodes in my library? (like constructing these functions with the compiler? (don't think so but better to ask))
Edit
There's news! I got my own answer, and i'll post it (but it's a bit long)
(by the way, english is not my native language so if i made an error, said me so, i'll edit)
doing the C++ -> your script call. This is c++11 by the way
You will need some form of packer that can take a type and add it in.
class SomeClassYouCanCallAScriptFunction {
// the order of these templates matter or else
// the one bellow will not be able to find the one higher
template<class T, class... Args>
callFunction(string name){
// run your code to call your scripted function
// arguments has the arguments array
}
template<class T, class... Args>
callFunction(string name, T var){
// last one
// either this
arguments.pack<T>(var);
// or this
arguments.pack(to_string(var));
// or the like
// now do the next one
callFunction(name);
}
template<class T, class... Args>
callFunction(string name, T var, Args... args){
// either this
arguments.pack<T>(var);
// or this
arguments.pack(to_string(var));
// or the like
// now do the next one
callFunction(name, args...);
}
}
someClass.callFunction("scriptFunc", "ya", 42, someVectMaybe);
The otherway around the best you can do is provide a arguments variable and let the user get a argument passed in like arguments.get<T>(index)
Detail On the Context
For more Understanding (and if one want to re-use my solution), I'l detail the context of what i'm doing:
There's a top level (accessible only by the cTVScript::Executor)
And a low level (Visible (or almost) by the user)
top Level (or Non-typed part)
/*
* Non-Typed Part
*/
class Loadable{
public:
virtual std::string getAsString() { return ""; }
};
struct parametersPack{
public:
Loadable* returnValue;
std::vector<Loadable*> arguments;
};
Low Level (or typed-part)
class StringLoadable : public Loadable{
private:
std::string value;
public:
StringLoadable(std::string _s) : value(_s) {}
virtual std::string getAsString() { return value; }
virtual std::string get() { return value; }
virtual std::string& getRef() { return value; }
};
template<typename type>
class primaryLoadable : public Loadable{
private:
type value;
public:
primaryLoadable(type _v) : value(_v) {}
virtual std::string getAsString() { return std::to_string(value); }
type get() {return value;}
type& getRef() {return value;}
};
Save Function with non-matching prototype
A Parent Function Class (for stocking them):
class functionLoadable : public Loadable{
public:
virtual void call(parametersPack& pack) = 0;
};
And Sub-Function (one with void return and other with typed-Return)
/*
* Static Loadable Function
*/
template <typename Return, typename... Arguments>
class StaticLoadableFunction : public functionLoadable{
private:
Return (*fn)(Arguments...);
public:
Return calling(Arguments... args) {
Return value = fn(args...);
return (value);
}
virtual void call(parametersPack& pack) {
Unpacker::applyFunc(pack.arguments, fn);
}
StaticLoadableFunction(Return (*_fn)(Arguments...)) : fn(_fn){}
};
template <typename... Arguments>
class StaticLoadableFunction<void, Arguments...> : public functionLoadable{
private:
void (*fn)(Arguments...);
public:
void calling(Arguments... args) {
fn(args...);
}
virtual void call(parametersPack& pack) {
Unpacker::applyFunc(pack.arguments, fn);
}
StaticLoadableFunction(void (*_fn)(Arguments...)) : fn(_fn){}
};
Now the work of the unpacker
First I need to unpack my arguments from my std::vector
/*
* Unpacking all arguments
*/
template<unsigned int N>
struct helper;
template<unsigned int N>
struct helper{
template <typename ReturnType, typename... Arguments, typename ...final>
static ReturnType applyFunc(std::vector<Loadable*> parameters, ReturnType (*fn)(Arguments...), final&&... args) {
return (helper<N - 1>::applyFunc
(parameters, fn,
convertLoadableTo< typename parametersType<N - 1, Arguments...>::type >
::transform(parameters[N-1]),
args...));
}
};
template<>
struct helper<0>{
template <typename ReturnType, typename ...Arguments, typename ...final>
static ReturnType applyFunc(std::vector<Loadable*> parameters, ReturnType (*fn)(Arguments...), final&&... args) {
return (fn( args... ));
}
};
template <typename ReturnType, typename ...Arguments>
ReturnType applyFunc(std::vector<Loadable*> args, ReturnType (*fn)(Arguments...)) {
return (helper<sizeof...(Arguments)>::applyFunc(args, fn));
}
I know want to know wich type are in each recursion:
/*
* Getting Parameters type N in variadic Templates
*/
template <int N, typename... T>
struct parametersType;
template <typename T0, typename... T>
struct parametersType<0, T0, T...> {
typedef T0 type;
};
template <int N, typename T0, typename... T>
struct parametersType<N, T0, T...> {
typedef typename parametersType<N-1, T...>::type type;
};
And then downcast my Loadable* object into primaryLoadable<> or StringLoadable
/*
* Treat For Each Type
*/
template <typename arg>
struct convertLoadableTo;
template <typename arg>
struct convertLoadableTo{ // int, double...etc
static arg transform(Loadable* l) {
primaryLoadable<arg>* _l =
dynamic_cast< primaryLoadable<arg>* >(l);
if (!_l)
throw;
return (_l->get());
}
};
template <typename arg>
struct convertLoadableTo<arg&>{ // int&, double&...etc
static arg& transform(Loadable* l) {
primaryLoadable<arg>* _l =
dynamic_cast< primaryLoadable<arg>* >(l);
if (!_l)
throw;
return (_l->getRef());
}
};
template <>
struct convertLoadableTo<std::string>{ // int&, double&...etc
static std::string transform(Loadable* l) {
StringLoadable* _l =
dynamic_cast< StringLoadable* >(l);
if (!_l)
throw;
return (_l->get());
}
};
template <>
struct convertLoadableTo<std::string&>{ // int&, double&...etc
static std::string& transform(Loadable* l) {
StringLoadable* _l =
dynamic_cast< StringLoadable* >(l);
if (!_l)
throw;
return (_l->getRef());
}
};
That's the end!
If you wanna know more detail please mp me!
Pretty complicated (and bad) title, here's what I mean by example:
struct type1 {};
struct type2 {};
struct type3 {};
template< typename TYPE >
struct interface {
virtual void f( TYPE ) = 0;
};
struct processor {
template< typename TYPE >
void f( TYPE ) {
// something + for some TYPE-s have specializations, but it's irrelevant
}
};
struct der: interface< type1 >, interface< type2 >, interface< type3 > {
processor p;
void f( type1 t ){ p.f( t ); }
void f( type2 t ){ p.f( t ); }
void f( type3 t ){ p.f( t ); }
};
Is there any tricky way to avoid all overrides in der? In the real case, der inherits interface 10 times (with different template types and it could be extended in the future). And it's rather ugly to have 10+ overrides of f when their bodies are the same.
processor could be changed to anything, also der::p could be some container, holding a template-d processor, etc.
It sounds like I want to have a virtual template member function f, which is not allowed.
I thought about using a macro, but I don't like that idea.
EDIT Note: can't use c++11, unfortunately. And can't change typeN types, which are not in hierarchy.
C++03 solutions
(See KerrekSB's answer for solutions using C++11 features)
You can use another layer of inheritance and CRTP to dispatch the calls to your processor:
template< typename TYPE, class ProcessorHolder >
struct processorDispatch : interface<TYPE> {
virtual void f( TYPE t ) override {
processor& p = static_cast<ProcessorHolder*>(this)->p; //CRTP --> explicit downcast
p.f(t);
}
};
And use it as
struct der: processorDispatch< type1,der >, processorDispatch< type2,der >, processorDispatch< type3,der > {
processor p;
//make f visible - either
using processorDispatch< type1,der >::f;
using processorDispatch< type2,der >::f;
using processorDispatch< type3,der >::f;
//or
template <typename TYPE>
void f(TYPE t) {
processorDispatch<TYPE, der>::f(t);
}
}
};
A take at Kerrek's non-CRTP-solution, but "C++11-free" vía base class chaining:
struct der_base {
processor p;
};
template <class TYPE, class Base = der_base>
struct der_t : Base, interface<TYPE> {
void f(TYPE t) { this->p.f(t); }
using Base::f;
};
template <class TYPE>
struct der_t<TYPE, der_base> : der_base, interface<TYPE> {
void f(TYPE t) { this->p.f(t); }
};
And then use
typedef der_t<type1, der_t<type2, der_t<type3> > > der;
You could make der a template:
template <typename ...> struct der;
template <> struct der<>
{
processor p;
};
template <typename Base, typename ...Rest>
struct der<Base, Rest...> : der<Rest...>, interface<Base>
{
void f(Base x) { this->p.f(x); }
};
Then use:
der<type1, type2, type3> d;
Here's an alternative design using CRTP:
template <typename Actual, typename Base> struct FImpl : Base
{
void f(Base x) { static_cast<Actual*>(this)->p.f(x); }
};
template <typename ...T> struct der : FImpl<der, T>...
{
processor p;
};
Another solution, similar to #ArneMertz 's one, could be (but it involves several instances of processor - one per type, so could be inappropriate for some cases):
struct type1 {};
struct type2 {};
struct type3 {};
template< typename TYPE >
struct interface
{
virtual void f( TYPE ) = 0;
};
template< typename TYPE >
struct processor
{
void f( TYPE t ){ std::cout << typeid( t ).name() << std::endl; }
};
template< typename TYPE >
struct interface_impl: interface< TYPE >
{
processor< TYPE > p_;
void f( TYPE t )
{
p_.f( t );
}
};
struct final: interface_impl< type1 >, interface_impl< type2 >, interface_impl< type3 >
{
template< typename TYPE >
void f( TYPE t )
{
interface_impl< TYPE >::f( t );
}
};
This is almost the same, with one difference only - processor is added in the "middle" class. In terms of #Arne's answer:
make processor template class
processorDispatch has a member processor with the same TYPE
This:
eliminates the static_cast
simplifies the inheritance (one type vs two)
Or even processor could be defined inside interface_impl, like
template< typename TYPE >
struct interface_impl: interface< TYPE >
{
struct processor
{
void f( TYPE t ){ std::cout << typeid( t ).name(); }
} p_;
void f( TYPE t )
{
p_.f( t );
}
};
I'm still trying to get the swing of metaprogramming, and I'm stumped.
What's I'd like to do is create a class/struct/whatever, supply it a std::tuple and have it automatically generate member functions based on the object types in the tuple. The goal is to have classes derive from MessageHandler
e.g.
typedef std::tuple< MessageA, MessageB, MessageC > MessageSet;
template< class T >
class MessageHandler
{
// some magic metaprogramming would "create"...
virtual void processMsg( const MessageA& ) = 0;
virtual void processMsg( const MessageB& ) = 0;
virtual void processMsg( const MessageC& ) = 0;
};
I've read that you can't have virtual functions in templates, but I didn't know if that was still true for C++11.
Thanks.
The answer is variadic template, partial specialization, and inheritance as:
//primary template!
template<typename T>
class MessageHandler;
//variadic template, partial specialization and inheritance!
template<typename H, typename ...T>
class MessageHandler<std::tuple<H,T...>> : public MessageHandler<std::tuple<T...>>
{
virtual void processMsg( const H& ) = 0;
};
template<typename T>
class MessageHandler<std::tuple<T>>
{
virtual void processMsg( const T& ) = 0;
};
You don't need tuple to do that:
struct MessageA{};struct MessageB{};struct MessageC{};
template <typename T>
struct message_interface {
virtual void processMessage(const T& t) = 0;
};
template< typename... Args >
struct message_handler : public message_interface<Args>...
{};
struct message_impl : message_handler<MessageA, MessageB, MessageC>
{
void processMessage(const MessageA&){}
void processMessage(const MessageB&){}
void processMessage(const MessageC&){}
};
int main()
{
message_impl i;
return 0;
}
It would probably be a good idea to check if the argument list is unique and static assert on that. Also make sure it does not contain reference types or other undesirables. Those will usually end up as errors when you try to form the argument type but it will safe your users some trouble.
EDIT: If you absolutely require to support tuple add a specialization:
template< typename... Args >
struct message_handler< std::tuple<Args...> > : public message_interface<Args>...
{};