I'm trying to come up with a better way of representing the following:
using InsBase0 = std::tuple<std::string, std::function<void()>>;
static const std::array<InsBase0, 1> ins0_bases = {{
{"NOP", 0x0},
}};
using InsBase1 = std::tuple<std::string, std::function<void(const std::string &)>>;
static const std::array<InsBase1, 7> ins1_bases = {{
{"INC", 0x0},
{"DEC", 0x0},
{"AND", 0x0},
{"OR", 0x0},
{"XOR", 0x0},
{"CP", 0x0},
{"SUB", 0x0},
}};
using InsBase2 = std::tuple<std::string, std::function<void(const std::string &, const std::string&)>>;
static const std::array<InsBase2, 6> ins_bases = {{
{"LD", 0x0},
{"ADD", 0x0},
{"ADC", 0x0},
{"SBC", 0x0},
{"JP", 0x0},
{"JR", 0x0},
}};
(utterly contrived example, imagine functions in place of 0x0 and something more sane like a map instead of an array or a struct instead of the tuple)
The context is that this is an assembler, so I need to map instructions to functions.
In a perfect world, I'd like to be able to put all of the instructions into one array/container (with an additional args member to denote the number of args the function takes), but I'd be happy with not duplicating the definitions with StructName0 as well
Two bits of metaprogramming helpers:
template<std::size_t I>
using index=std::integral_constant<std::size_t, I>;
template<class T> struct tag_t {constexpr tag_t(){};};
template<class T> tag_t<T> tag{};
template<std::size_t, class T>
using indexed_type = T;
Now we define an enum type for each of the argument counts:
enum class zero_op:std::size_t { NOP };
enum class one_op:std::size_t { INC };
enum class two_op:std::size_t { ADD };
Next, a mapping from the types to the argument count:
constexpr index<0> args( tag_t<zero_op> ) { return {}; }
constexpr index<1> args( tag_t<one_op> ) { return {}; }
constexpr index<2> args( tag_t<two_op> ) { return {}; }
This takes a template and a count and a type, and repeatedly passes the type to the template:
template<template<class...>class Z, class T, class Indexes>
struct repeat;
template<template<class...>class Z, class T, std::size_t I>
struct repeat<Z, T, index<I>>:
repeat<Z, T, std::make_index_sequence<I>>
{};
template<template<class...>class Z, class T, std::size_t...Is>
struct repeat<Z, T, std::index_sequence<Is...>> {
using type=Z<indexed_type<Is, T>...>;
};
template<template<class...>class Z, class T, std::size_t N>
using repeat_t = typename repeat<Z, T, index<N>>::type;
We use this to build our std::function signatures:
template<class...Args>
using void_call = std::function<void(Args...)>;
template<std::size_t N, class T>
using nary_operation = repeat_t< void_call, T, N >;
and nary_operation< 3, std::string const& > is std::function<void(std::string const&,std::string const&,std::string const&)>.
We use this to create a compile time polymorphic table:
template<class...Es>
struct table {
template<class E>
using operation = nary_operation<args(tag<E>), std::string const&>;
template<class E>
using subtable = std::map< E, operation<E> >;
std::tuple< subtable<Es>... > tables;
template<class E>
operation<E> const& operator[]( E e ) {
return std::get< subtable<E> >( tables )[e];
}
};
or something like that.
If you have an intance of table<zero_op, one_op, two_op> bob, you can do
bob[ zero_op::NOP ]();
or
bob[ zero_op::INC ]("foo");
or
bob[ zero_op::ADD ]("foo", "bar");
The type of the enum in [] changes the type of the function object returned.
The above probably has typos.
But, the end result is type-safe.
I couldn't figure out a way to store all operations in one structure and still have compile time checks. Yet it is possible to check the number of passed values at runtime.
#include <iostream>
#include <functional>
#include <string>
#include <unordered_map>
class operation
{
using op0_funcptr = void(*)();
using op1_funcptr = void(*)(const std::string&);
using op2_funcptr = void(*)(const std::string&, const std::string&);
using op0_func = std::function<void()>;
using op1_func = std::function<void(const std::string&)>;
using op2_func = std::function<void(const std::string&, const std::string&)>;
std::tuple<
op0_func,
op1_func,
op2_func> m_functions;
public:
operation() :m_functions(op0_func(), op1_func(), op2_func()) {}
operation(const op0_func& op) :m_functions(op, op1_func(), op2_func()) {}
operation(const op0_funcptr& op) :m_functions(op, op1_func(), op2_func()) {}
operation(const op1_func& op) :m_functions(op0_func(), op, op2_func()) {}
operation(const op1_funcptr& op) :m_functions(op0_func(), op, op2_func()) {}
operation(const op2_func& op) :m_functions(op0_func(), op1_func(), op) {}
operation(const op2_funcptr& op) :m_functions(op0_func(), op1_func(), op) {}
operation(const operation& other) = default;
operation(operation&& other) = default;
void operator()() { std::get<op0_func>(m_functions)(); }
void operator()(const std::string& p1) { std::get<op1_func>(m_functions)(p1); }
void operator()(const std::string& p1, const std::string& p2) { std::get<op2_func>(m_functions)(p1, p2); }
};
void nop()
{
std::cout << "NOP" << std::endl;
}
void inc(const std::string& p1)
{
std::cout << "INC(" << p1 << ")" << std::endl;
}
void add(const std::string& p1, const std::string& p2)
{
std::cout << "ADD(" << p1 << ", " << p2 << ")" << std::endl;
}
std::unordered_map<std::string, operation> operations{ {
{ "NOP", nop },
{ "INC", inc },
{ "ADD", add }
} };
int main(int argc, char** argv)
{
operations["NOP"]();
operations["INC"]("R1");
operations["ADD"]("R2", "R3");
operations["ADD"]("R2"); //Throws std::bad_function_call
}
It's by far not the best solution, but it works.
If you want to make the access faster you can also try to change the lower part to something like this:
enum class OP : size_t
{
NOP,
INC,
ADD,
NUM_OPS
};
std::array<operation, (size_t)OP::NUM_OPS> operations{ nop ,inc, add };
int main(int argc, char** argv)
{
operations[(size_t)OP::NOP]();
operations[(size_t)OP::INC]("R1");
operations[(size_t)OP::ADD]("R2", "R3");
//operations[(size_t)OP::ADD]("R2"); //Throws std::bad_function_call
}
I suggest the use of single std::map where the key is the name of the function (NOP, AND, ADD, etc.).
Using inheritance, a trivial base class, a std::function wrapper...
Not really elegant, I suppose, but...
#include <map>
#include <memory>
#include <iostream>
#include <functional>
struct funBase
{
// defined only to permit the dynamic_cast
virtual void unused () const {};
};
template <typename R, typename ... Args>
struct funWrap : public funBase
{
std::function<R(Args...)> f;
funWrap (R(*f0)(Args...)) : f { f0 }
{ }
};
template <typename R, typename ... Args>
std::unique_ptr<funBase> makeUFB (R(*f)(Args...))
{ return std::unique_ptr<funBase>(new funWrap<R, Args...>(f)); }
template <typename F, typename T, bool = std::is_convertible<F, T>::value>
struct getConv;
template <typename F, typename T>
struct getConv<F, T, true>
{ using type = T; };
template <typename F, typename T>
struct getConv<F, T, false>
{ };
template <typename ... Args>
void callF (std::unique_ptr<funBase> const & fb, Args ... args)
{
using derType = funWrap<void,
typename getConv<Args, std::string>::type const & ...>;
derType * pdt { dynamic_cast<derType *>(fb.get()) };
if ( nullptr == pdt )
std::cout << "call(): error in conversion" << std::endl;
else
pdt->f(args...);
}
void fNop ()
{ std::cout << "NOP!" << std::endl; }
void fAnd (std::string const & s)
{ std::cout << "AND! [" << s << ']' << std::endl; }
void fAdd (std::string const & s1, std::string const & s2)
{ std::cout << "ADD! [" << s1 << "] [" << s2 << ']' << std::endl; }
int main()
{
std::map<std::string, std::unique_ptr<funBase>> fm;
fm.emplace("NOP", makeUFB(fNop));
fm.emplace("AND", makeUFB(fAnd));
fm.emplace("ADD", makeUFB(fAdd));
callF(fm["NOP"]); // print NOP!
callF(fm["AND"], "arg"); // print AND! [arg]
callF(fm["ADD"], "arg1", "arg2"); // print ADD! [arg1] [arg2]
callF(fm["ADD"], "arg1"); // print call(): error in conversion
//callF(fm["ADD"], "arg1", 12); // compilation error
return 0;
}
P.s.: works with C++11 too.
Instead of having a std::string argument for your functions, you could use a std::vector<std::string>, so you could store multiple arguments.
That would relate to something like :
using function_t = std::function<void(const std::vector<std::string>&)>;
static const std::unordered_map<std::string, function_t> instructions =
{
{"INC", somefunc},
...
};
And then to call the proper instruction :
std::vector<std::string> arguments = { "zob", "zeb" };
auto result = instructions["INC"](arguments);
Edit :
Here's the rest of how I would do it, to prove you it's not that long :
/**
* Your instruction type. Contains its name,
* the function to call, and the number of args required
*/
struct Instruction {
using function_t = std::function<void(std::vector<std::string>)>;
std::string name;
function_t function;
std::size_t numargs;
Instruction(const std::string& name = "undefined", const function_t& function = function_t(), std::size_t numargs = 0)
: name(name)
, function(function)
, numargs(numargs) {}
}
/**
* Your instruction set. It contains the instructions you want to register in.
* You can call the instructions safely through this
*/
struct InstructionSet {
std::unordered_map<std::string, Instruction> instructions;
void callInstruction(const std::string& inst_name, const std::vector<std::string>& arguments) {
if (!instructions.count(inst_name))
return; // no instruction named "inst_name", return or throw something relevant
auto instruction = instructions[inst_name];
if (instruction.numargs != arguments.size())
return; // too many / not enough parameters, return or throw something relevant
instruction.function(arguments);
}
void registerInstruction(const Instruction& instruction) {
instructions[instruction.name] = instruction;
}
};
int main() {
InstructionSet instruction_set;
instruction_set.registerInstruction(Instruction(
"INC",
[](const std::vector<std::string>& arguments) {
bake_cookies_plz(arguments);
},
2)
);
instruction_set.callInstruction("INC", { "1", "2" });
return 0;
}
Note 1 : in this example, the InstructionSet is responsible for checking the number of arguments passed, but the functions could do it themselves. I would do that if there was a possibility of variable arguments count
Note 2 : the registering part is not quite elegant with lambdas, but it's quick to write
Note 3 : if you want more type safety for your arguments, go check max66 answer to get an idea of how to master templates in this situation
Related
I would like to let compiler deduce partially class template arguments from constructor.
The motivation is to write a protocol library where the existance (here the length in bits) of certain data depends of the value of last variable, so a conditional class must be used to model this.
The c++ code I want to implement should work like this, but I would like to implement it in a more expressive and simplified way, without having to set all the parameters in the template but leaving compiler deduce them:
Coliru link: https://coliru.stacked-crooked.com/a/bb15abb2a9c09bb1
#include <iostream>
template<typename T1, typename T2, typename F, int... Ints>
struct If : T1
{
const T2& condition;
constexpr If(const T2& cond) : condition(cond) {}
constexpr int bits() { return check() ? T1::bits : 0; }
constexpr bool check()
{
return (F{}(Ints, condition.value) || ...);
}
};
struct Variable1
{
int value{};
static constexpr int bits{ 5 };
};
struct Variable2
{
int value{};
static constexpr int bits{ 8 };
};
struct Datagram
{
Variable1 var1;
If<Variable2, Variable1, std::equal_to<int>, 1, 2> var2{ var1 };//It compiles and works OK under c++17. What I have...
//If<Variable2> var2{ var1, std::equal_to<int>{}, 1, 2 };// ...what I wish
};
int main()
{
Datagram data;
data.var1.value = 0;
std::cout << data.var2.bits() << "\n";//must be 0
data.var1.value = 1;
std::cout << data.var2.bits() << "\n";//must be 8
data.var1.value = 2;
std::cout << data.var2.bits() << "\n";//must be 8
}
Is this possible?
The concept you are probably looking for is "type erasure", e.g. via std::function. Something along these lines:
template<typename T1>
struct If : T1
{
std::function<bool()> checker_;
template <typename T2, typename F, typename... Args>
constexpr If(const T2& cond, F&& f, Args&&... args)
: checker_([=, &cond]() { return (f(args, cond.value) || ...); })
{}
constexpr int bits() { return check() ? T1::bits : 0; }
constexpr bool check()
{
return checker_();
}
};
Demo
I am trying to implement an std::unordered_map that returns pairs of either double, int or std::string. The keys for the map are std::strings. Below is what I have tried so far:
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
#include <unordered_map>
#include <utility>
#include <vector>
// A base class for boundary class
class Boundbase {
public:
Boundbase(){};
virtual ~Boundbase(){};
};
// A different map of boundaries for each different data type
template <class dType>
class Boundary : public Boundbase {
std::pair<dType, dType> bpair;
public:
//Constructor
Boundary(const std::string &lbound,
const std::string &ubound) {
setbound(lbound, ubound);
};
//A method to set boundary pair
void setbound(const std::string &lbound,
const std::string &ubound);
// A method to get boundary pair
std::pair<dType, dType> getbound() {return bpair;}
};
// Class to hold the different boundaries
class Boundaries {
std::unordered_map<std::string, Boundbase*> bounds;
public:
//Constructor
Boundaries() {};
// A method to set boundary map
void setboundmap(std::unordered_map<std::string,
std::vector<std::string>> xtb);
// A template to get boundaries.
std::unordered_map<std::string, Boundbase*> getbounds()
{return bounds;}
};
// A method to set covariate boundary
template <class dType> void
Boundary<dType>::setbound(const std::string &lbound,
const std::string &ubound) {
dType val;
std::istringstream isa(lbound);
while(isa >> val) {
bpair.first = val;
}
std::istringstream isb(ubound);
while(isb >> val) {
bpair.second = val;
}
}
// A method to set boundary map
void Boundaries::setboundmap(std::unordered_map<std::string,
std::vector<std::string>> xtb) {
for(auto s : xtb) {
char type = s.second[1][0];
switch(type) {
case 'd': {
std::pair<std::string, Boundbase*> opair;
opair.first = s.first;
opair.second = new Boundary<double>(
s.second[2], s.second[3]);
bounds.insert(opair);
}
break;
case 'i': {
std::pair<std::string, Boundbase*> opair;
opair.first = s.first;
opair.second = new Boundary<int>(
s.second[2], s.second[3]);
bounds.insert(opair);
break;
}
case 'c': {
std::pair<std::string, Boundbase*> opair;
opair.first = s.first;
opair.second = new Boundary<std::string>(
s.second[2], s.second[2]);
bounds.insert(opair);
break;
}
}
}
}
This compiles ok using g++. When I try to run it though ( as follows):
int main() {
Data D;
Boundaries B;
std::ifstream iss("tphinit.txt");
D.read_lines(iss);
auto dbounds = D.get_xtypebound();
B.setboundmap(dbounds);
auto tbounds = B.getbounds();
auto sbound = tbounds["X1"];
std::cout << sbound->bpair.first << ","
<< sbound->bpair.second << std::endl;
}
I get 'class Boundbase' has no member named 'bpair' which is true because I am pointing to the base class and not the derived class. As far as I can tell, trying to get the derived member bpair requires that I use the visitor pattern. Now, it is clear that I am noob so when I had a look at different ways of doing this on SO I was a little in over my head (no reflection on the authors, just on my inexperience).
So my main question is: Is this the best and simplest way to go about this? I would like to avoid boost::variant if at all possible (mainly for the sake of purity: this cannot be that difficult). A sub-question is whether I have to use the visitor pattern or is there a better/simpler way to get the member pbair?
I will have to perform this lookup many times so I am hoping to make it as fast as possible but using the stl for the sake of simplicity.
Make your values std variants over the 3 types.
Failing that, boost variant.
Std and boost variant really are what you want. You'll end up implementing some subset of its implementation.
Failing that, find a tutorial on how to implement ones of them, or use std any. Failing that, dynamic casts around an otherwise useless wrapper type with a virtual dtor stored in a unique ptr, or do manual RTTI with try get methods.
This just gets increasingly ugly and/or inefficient however.
Boost variant, and std variant from it, was implemented for a reason, and that reason was solving the exact problem you are describing in an efficient manner.
#include <tuple>
#include <utility>
#include <string>
template<class...Ts>
struct destroy_helper {
std::tuple<Ts*...> data;
destroy_helper( std::tuple<Ts*...> d ):data(d){}
template<class T>
static void destroy(T* t){ t->~T(); }
template<std::size_t I>
void operator()(std::integral_constant<std::size_t, I>)const {
destroy( std::get<I>( data ) );
}
};
struct construct_helper {
template<class T, class...Args>
void operator()(T* target, Args&&...args)const {
::new( (void*)target ) T(std::forward<Args>(args)...);
}
};
template<std::size_t...Is>
struct indexes {};
template<std::size_t N, std::size_t...Is>
struct make_indexes:make_indexes<N-1, N-1, Is...> {};
template<std::size_t...Is>
struct make_indexes<0, Is...>{
using type=indexes<Is...>;
};
template<std::size_t N>
using make_indexes_t = typename make_indexes<N>::type;
template<class F>
void magic_switch( std::size_t i, indexes<>, F&& f ) {}
template<std::size_t I0, std::size_t...Is, class F>
void magic_switch( std::size_t i, indexes<I0,Is...>, F&& f )
{
if (i==I0) {
f( std::integral_constant<std::size_t, I0>{} );
return;
}
magic_switch( i, indexes<Is...>{}, std::forward<F>(f) );
}
template<class T0>
constexpr T0 max_of( T0 t0 ) {
return t0;
}
template<class T0, class T1, class...Ts>
constexpr T0 max_of( T0 t0, T1 t1, Ts... ts ) {
return (t1 > t0)?max_of(t1, ts...):max_of(t0, ts...);
}
template<class...Ts>
struct Variant{
using Data=typename std::aligned_storage< max_of(sizeof(Ts)...), max_of(alignof(Ts)...)>::type;
std::size_t m_index=-1;
Data m_data;
template<std::size_t I>
using alternative_t=typename std::tuple_element<I, std::tuple<Ts...>>::type;
using pointers=std::tuple<Ts*...>;
using cpointers=std::tuple<Ts const*...>;
template<class T> T& get(){ return *reinterpret_cast<T*>(&m_data); }
template<class T> T const& get() const { return *reinterpret_cast<T*>(&m_data); }
template<std::size_t I>
alternative_t<I>& get(){ return std::get<I>(get_pointers()); }
template<std::size_t I>
alternative_t<I> const& get()const{ return std::get<I>(get_pointers()); }
pointers get_pointers(){
return pointers( (Ts*)&m_data... );
}
cpointers get_pointers()const{
return cpointers( (Ts const*)&m_data... );
}
std::size_t alternative()const{return m_index;}
void destroy() {
if (m_index == -1)
return;
magic_switch(m_index, make_indexes_t<sizeof...(Ts)>{}, destroy_helper<Ts...>(get_pointers()));
}
template<std::size_t I, class...Args>
void emplace(Args&&...args) {
destroy();
construct_helper{}( std::get<I>(get_pointers()), std::forward<Args>(args)... );
m_index = I;
}
Variant()=default;
Variant(Variant const&)=delete;//todo
Variant&operator=(Variant const&)=delete;//todo
Variant(Variant &&)=delete;//todo
Variant&operator=(Variant &&)=delete;//todo
~Variant(){destroy();}
};
int main() {
Variant<int, double, std::string> bob;
bob.emplace<0>( 7 );
bob.emplace<1>( 3.14 );
bob.emplace<2>( "hello world" );
}
here is a really simple variant interface.
The hard part is turning a runtime index into which of the compile time indexes you want to use. I call that the magic switch problem.
You might also want to implement apply visitor.
...
Or...
template<class T>
struct Derived;
struct Base {
virtual ~Base() {}
template<class T>
friend T* get(Base* base) {
Derived<T>* self = dynamic_cast<T*>(base);
return self?&self.t:nullptr;
}
template<class T>
friend T const* get(Base const* base) {
Derived<T> const* self = dynamic_cast<T const*>(base);
return self?&self.t:nullptr;
}
};
template<class T>
struct Derived:Base {
Derived(T in):t(std::move(in)){}
T t;
};
std::unordered_map<std::string, std::unique_ptr<Base>> map;
map["hello"] = std::unique_ptr<Base>( new Derived<int>(-1) );
map["world"] = std::unique_ptr<Base>( new Derived<double>(3.14) );
int* phello = get<int>(map["hello"]);
if (phello) std::cout << *hello << "\n";
double* pworld = get<double>(map["world"]);
if (pworld) std::cout << *world << "\n";
which is a seriously bargain-basement std::any.
My question here is similar to this post expect that I have more than one template argument and string. Thus, the setup is
class base_class; // no template args
template<typename T, typename U, typename V>
class child_class : public base_class;
I have a limited number of implemented types for T, U and V which I want to select at runtime given three strings. So as the question in cited post, I could do something like
std::unique_ptr<base_class> choose_arg1(
std::string T_str, std::string U_str, std::string v_str){
if(T_str == "int"){
return(choose_arg2<int>(U_str, V_str));
} else if(T_str == "char"){
return(choose_arg2<char>(U_str, V_str));
} // ...
}
template<typename T>
std::unique_ptr<base_class> choose_arg2(std::string U_str, std::string v_str){
if(U_str == "int"){
return(choose_arg3<T, int>(V_str));
} else if(U_str == "char"){
return(choose_arg3<T, char>(V_str));
} // ...
}
template<typename T, typename U>
std::unique_ptr<base_class> choose_arg3(std::string v_str){
if(v_str == "int"){
return(std::make_unique<child_class<T, U, int>>());
} else if(v_str == "char"){
return(std::make_unique<child_class<T, U, char>>());
} // ...
}
but is there a better way? I have less than 5^3 combination for the record.
I suggest to develop a template helper struct with a couple of static func() methods
template <typename ... Ts>
struct choose_args_h
{
using retT = std::unique_ptr<base_class>;
template <typename ... Args>
static retT func (std::string const & s, Args const & ... args)
{
if ( s == "int" )
return choose_args_h<Ts..., int>::func(args...);
else if ( s == "char" )
return choose_args_h<Ts..., char>::func(args...);
// else ...
}
static retT func ()
{ return std::make_unique<child_class<Ts...>>(); }
};
so you can write a choose_args() func simply as follows
template <typename ... Args>
std::unique_ptr<base_class> choose_args (Args const & ... args)
{ return choose_args_h<>::func(args...); }
The following is a full working example
#include <string>
#include <memory>
class base_class
{ };
template <typename, typename, typename>
class child_class : public base_class
{ };
template <typename ... Ts>
struct choose_args_h
{
using retT = std::unique_ptr<base_class>;
template <typename ... Args>
static retT func (std::string const & s, Args const & ... args)
{
if ( s == "int" )
return choose_args_h<Ts..., int>::func(args...);
else if ( s == "char" )
return choose_args_h<Ts..., char>::func(args...);
// else ...
}
static retT func ()
{ return std::make_unique<child_class<Ts...>>(); }
};
template <typename ... Args>
std::unique_ptr<base_class> choose_args (Args const & ... args)
{ return choose_args_h<>::func(args...); }
int main ()
{
auto p0 = choose_args("int", "char", "int");
auto p1 = choose_args("int", "char", "char");
}
Shown in this post is a C++17 solution with compile-time configuration of the allowed types and corresponding keys via the type Argmaps. The lookup is done by a compile-time loop.
C++11 does not support generic lambdas which are required for the compile-time loops used here. Instead, one could perform the lookup by template meta-programming with the "indices trick" (as in this online demo), but that feels too complicated and I prefer the std::map approach anyway. Note that my linked C++11 attempt could call the constructor twice if the keys are not unique.
#include <iostream>
#include <memory>
#include <string>
#include "loop.hpp"
template<class... Ts> struct Types {
static constexpr size_t size = sizeof...(Ts);
template<size_t i>
using At = std::tuple_element_t<i, std::tuple<Ts...>>;
};
template<class... Ts> constexpr Types<Ts...> to_types(Ts...) { return {}; }
template<auto... cs> struct Str {
operator std::string() const {
constexpr auto list = std::initializer_list<char>{cs...};
return std::string{list.begin(), list.end()};
}
};
template<class Char, Char... cs>
constexpr auto operator""_c() {
return Str<cs...>{};
}
//////////////////////////////////////////////////////////////////////////////
struct Base {
virtual void identify() const = 0;
};
template<class... Ts>
struct Derived : Base {
virtual void identify() const override {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
using Ptr = std::unique_ptr<Base>;
//////////////////////////////////////////////////////////////////////////////
template<class Argmaps, class Args=Types<>>
struct choose_impl;
template<class Map0, class... Maps, class... Args>
struct choose_impl<Types<Map0, Maps...>, Types<Args...>> {
static constexpr size_t pos = sizeof...(Args);
template<class S0, class... Ss>
static Ptr get(S0 s0, Ss... ss) {
Ptr ret{nullptr};
using namespace Loop;
loop(less<Map0::size>, [&] (auto i) {
using Argmapping = typename Map0::template At<i>;
using Key = typename Argmapping::template At<0>;
using Arg = typename Argmapping::template At<1>;
using Recursion = choose_impl<Types<Maps...>, Types<Args..., Arg>>;
if(std::string(Key{}) == s0) ret = Recursion::get(ss...);
});
if(!ret) {
std::cerr << "NOT MAPPED AT POS " << pos << ": " << s0 << std::endl;
std::terminate();
}
return ret;
}
};
template<class... Args>// all Args are resolved
struct choose_impl<Types<>, Types<Args...>> {
static Ptr get() {
return std::make_unique<Derived<Args...>>();
}
};
template<class Argmaps, class... Ss>
Ptr choose(Ss... ss) {
static_assert(Argmaps::size == sizeof...(Ss));
return choose_impl<Argmaps>::get(std::string(ss)...);
}
template<class V, class K>
auto make_argmapping(K) {
return Types<K, V>{};
}
//////////////////////////////////////////////////////////////////////////////
int main() {
using Argmaps = decltype(
to_types(
to_types(// first template parameter
make_argmapping<int>("int"_c),
make_argmapping<char>("char"_c),
make_argmapping<bool>("bool"_c)
),
to_types(// ... second ...
make_argmapping<double>("double"_c),
make_argmapping<long>("long"_c)
),
to_types(// ... third
make_argmapping<bool>("bool"_c)
)
)
);
choose<Argmaps>("int", "double", "bool")->identify();
choose<Argmaps>("int", "long", "bool")->identify();
choose<Argmaps>("char", "double", "bool")->identify();
choose<Argmaps>("char", "long", "bool")->identify();
choose<Argmaps>("bool", "double", "bool")->identify();
choose<Argmaps>("bool", "long", "bool")->identify();
// bad choice:
choose<Argmaps>("int", "int", "bool")->identify();
return 0;
}
loop.hpp from this unread answer:
#ifndef LOOP_HPP
#define LOOP_HPP
namespace Loop {
template<auto v> using Val = std::integral_constant<decltype(v), v>;
template<auto i> struct From : Val<i> {};
template<auto i> static constexpr From<i> from{};
template<auto i> struct Less : Val<i> {};
template<auto i> static constexpr Less<i> less{};
// `to<i>` implies `less<i+1>`
template<auto i> struct To : Less<i+decltype(i)(1)> {};
template<auto i> static constexpr To<i> to{};
template<auto i> struct By : Val<i> {};
template<auto i> static constexpr By<i> by{};
template<auto i, auto N, auto delta, class F>
constexpr void loop(From<i>, Less<N>, By<delta>, F f) noexcept {
if constexpr(i<N) {
f(Val<i>{});
loop(from<i+delta>, less<N>, by<delta>, f);
}
}
// overload with two arguments (defaulting `by<1>`)
template<auto i, auto N, class F>
constexpr void loop(From<i>, Less<N>, F f) noexcept {
loop(from<i>, less<N>, by<decltype(i)(1)>, f);
}
// overload with two arguments (defaulting `from<0>`)
template<auto N, auto delta, class F>
constexpr void loop(Less<N>, By<delta>, F f) noexcept {
loop(from<decltype(N)(0)>, less<N>, by<delta>, f);
}
// overload with one argument (defaulting `from<0>`, `by<1>`)
template<auto N, class F>
constexpr void loop(Less<N>, F f) noexcept {
using Ind = decltype(N);
loop(from<Ind(0)>, less<N>, by<Ind(1)>, f);
}
} // namespace Loop
#endif
http://coliru.stacked-crooked.com/a/5ce61617497c3bbe
As I noted in my comment, you could use a static map of string to function.
For your example code (slightly simplified to 2 template parameters to make it a little shorter), this would become:
#include <iostream>
#include <string>
#include <map>
#include <functional>
#include <memory>
class base_class { }; // no template args
template<typename T, typename U>
class child_class : public base_class { };
using ptr_type = std::unique_ptr<base_class>;
// Declarations
std::unique_ptr<base_class> choose_arg1 (std::string const & T_str,
std::string const & U_str);
template<typename T>
std::unique_ptr<base_class> choose_arg2 (std::string const & U_str);
// Definitions
std::unique_ptr<base_class> choose_arg1 (std::string const & T_str,
std::string const & U_str) {
using function_type = std::function<ptr_type(std::string const &)>;
using map_type = std::map<std::string, function_type>;
static const map_type ptrMap = {
{"int", choose_arg2<int> },
{"char", choose_arg2<char> }
};
auto ptrIter = ptrMap.find(T_str);
return (ptrIter != ptrMap.end()) ? ptrIter->second(U_str) : nullptr;
}
template<typename T>
std::unique_ptr<base_class> choose_arg2 (std::string const & U_str) {
using function_type = std::function<ptr_type()>;
using map_type = std::map<std::string, function_type>;
static const map_type ptrMap = {
{"int", []{ return std::make_unique<child_class<T, int>>(); } },
{"char", []{ return std::make_unique<child_class<T, char>>(); } }
};
auto ptrIter = ptrMap.find(U_str);
return (ptrIter != ptrMap.end()) ? ptrIter->second() : nullptr;
}
int main () {
std::cout << typeid(choose_arg1("int", "char")).name() << "\n";
std::cout << "[Done]\n";
}
Can I store in a container a list of member functions and then call them later, if they have different number of args.
I feel I'm just missing something small but this is how far I've got.
template<typename T>
class RPCServer
{
public:
RPCServer(const std::string host, const int port) {}
// Store the method pointers
template<typename F>
void register_method(const T discriminant, F func) {
m_callbacks.emplace_back(discriminant,func);
}
template<typename... Args>
void run(T subject, Args... args) {
auto func = std::find(std::begin(m_callbacks), std::end(m_callbacks), subject);
if (func != std::end(m_callbacks)) {
auto res = std::get<1>(*func)(args...); // This doesn't compile
}
}
~RPCServer() = default;
private:
// Store
std::vector<std::tuple<T, boost::any>> m_callbacks;
};
class Impl
{
public:
// RPC methods
void send_data(std::string data) {}
int get_details(int input) { return 0; }
};
Set up here
using namespace std::placeholders;
Impl impl;
RPCServer<std::string> server("localhost",1234);
server.register_method("foo", std::bind(&Impl::send_data, impl, _1));
server.register_method("bar", std::bind(&Impl::get_details, impl, _1));
server.run("foo", "blah"s); // This should call send_data with 'blah' as a arg
auto result = server.run("bar", 1); // Call get_details passing in 1
How do I store/retrieve a set of member functions type safely.
What about creating an adaptor template?
A proof-of-concept code:
#include <iostream>
#include <functional>
template<typename T0, typename... TS> struct FunCaller {
template<class F> FunCaller(F &&f): f(f) {}
template<typename... More> T0 operator()(TS &&... as, More &&...) {
return f(as...);
}
private:
std::function<T0(TS...)> f;
};
template<typename T0, typename... TS> inline FunCaller<T0, TS...> funCaller(T0(&&f)(TS...)) { return FunCaller<T0, TS...>(f); }
std::ostream &printSome(std::string const &s1, std::string const &s2) { return std::cout << s1 << ", " << s2 << std::endl; }
int main() {
auto omg = funCaller(printSome);
omg("Hello", "world!", "This", "is", "cocaine", "speaking");
}
In my current setup, I have a
typedef std::function<void (MyClass&, std::vector<std::string>) MyFunction;
std::map<std::string, MyFunction> dispatch_map;
And I register my functions in it with a macro. However, I have a problem with this: the parameters are passed as a vector of strings, which I have to convert inside the functions. I would rather do this conversion outside the functions, at the dispatcher level. Is this possible? The function signatures are known at compile time, and never change at run time.
You can get pretty far with variadic templates and some template/virtual techniques. With the following codes, you'll be able to do something like:
std::string select_string (bool cond, std::string a, std::string b) {
return cond ? a : b;
}
int main () {
Registry reg;
reg.set ("select_it", select_string);
reg.invoke ("select_it", "1 John Wayne"));
reg.invoke ("select_it", "0 John Wayne"));
}
output:
John
Wayne
Full implementation:
These codes are exemplary. You should optimize it to provide perfect forwarding less redundancy in parameter list expansion.
Headers and a test-function
#include <functional>
#include <string>
#include <sstream>
#include <istream>
#include <iostream>
#include <tuple>
std::string select_string (bool cond, std::string a, std::string b) {
return cond ? a : b;
}
This helps us parsing a string and putting results into a tuple:
//----------------------------------------------------------------------------------
template <typename Tuple, int Curr, int Max> struct init_args_helper;
template <typename Tuple, int Max>
struct init_args_helper<Tuple, Max, Max> {
void operator() (Tuple &, std::istream &) {}
};
template <typename Tuple, int Curr, int Max>
struct init_args_helper {
void operator() (Tuple &tup, std::istream &is) {
is >> std::get<Curr>(tup);
return init_args_helper<Tuple, Curr+1, Max>() (tup, is);
}
};
template <int Max, typename Tuple>
void init_args (Tuple &tup, std::istream &ss)
{
init_args_helper<Tuple, 0, Max>() (tup, ss);
}
This unfolds a function pointer and a tuple into a function call (by function-pointer):
//----------------------------------------------------------------------------------
template <int ParamIndex, int Max, typename Ret, typename ...Args>
struct unfold_helper;
template <int Max, typename Ret, typename ...Args>
struct unfold_helper<Max, Max, Ret, Args...> {
template <typename Tuple, typename ...Params>
Ret unfold (Ret (*fun) (Args...), Tuple tup, Params ...params)
{
return fun (params...);
}
};
template <int ParamIndex, int Max, typename Ret, typename ...Args>
struct unfold_helper {
template <typename Tuple, typename ...Params>
Ret unfold (Ret (*fun) (Args...), Tuple tup, Params ...params)
{
return unfold_helper<ParamIndex+1, Max, Ret, Args...> ().
unfold(fun, tup, params..., std::get<ParamIndex>(tup));
}
};
template <typename Ret, typename ...Args>
Ret unfold (Ret (*fun) (Args...), std::tuple<Args...> tup) {
return unfold_helper<0, sizeof...(Args), Ret, Args...> ().unfold(fun, tup);
}
This function puts it together:
//----------------------------------------------------------------------------------
template <typename Ret, typename ...Args>
Ret foo (Ret (*fun) (Args...), std::string mayhem) {
// Use a stringstream for trivial parsing.
std::istringstream ss;
ss.str (mayhem);
// Use a tuple to store our parameters somewhere.
// We could later get some more performance by combining the parsing
// and the calling.
std::tuple<Args...> params;
init_args<sizeof...(Args)> (params, ss);
// This demondstrates expanding the tuple to full parameter lists.
return unfold<Ret> (fun, params);
}
Here's our test:
int main () {
std::cout << foo (select_string, "0 John Wayne") << '\n';
std::cout << foo (select_string, "1 John Wayne") << '\n';
}
Warning: Code needs more verification upon parsing and should use std::function<> instead of naked function pointer
Based on above code, it is simple to write a function-registry:
class FunMeta {
public:
virtual ~FunMeta () {}
virtual boost::any call (std::string args) const = 0;
};
template <typename Ret, typename ...Args>
class ConcreteFunMeta : public FunMeta {
public:
ConcreteFunMeta (Ret (*fun) (Args...)) : fun(fun) {}
boost::any call (std::string args) const {
// Use a stringstream for trivial parsing.
std::istringstream ss;
ss.str (args);
// Use a tuple to store our parameters somewhere.
// We could later get some more performance by combining the parsing
// and the calling.
std::tuple<Args...> params;
init_args<sizeof...(Args)> (params, ss);
// This demondstrates expanding the tuple to full parameter lists.
return unfold<Ret> (fun, params);
}
private:
Ret (*fun) (Args...);
};
class Registry {
public:
template <typename Ret, typename ...Args>
void set (std::string name, Ret (*fun) (Args...)) {
funs[name].reset (new ConcreteFunMeta<Ret, Args...> (fun));
}
boost::any invoke (std::string name, std::string args) const {
const auto it = funs.find (name);
if (it == funs.end())
throw std::runtime_error ("meh");
return it->second->call (args);
}
private:
// You could use a multimap to support function overloading.
std::map<std::string, std::shared_ptr<FunMeta>> funs;
};
One could even think of supporting function overloading with this, using a multimap and dispatching decisions based on what content is on the passed arguments.
Here's how to use it:
int main () {
Registry reg;
reg.set ("select_it", select_string);
std::cout << boost::any_cast<std::string> (reg.invoke ("select_it", "0 John Wayne")) << '\n'
<< boost::any_cast<std::string> (reg.invoke ("select_it", "1 John Wayne")) << '\n';
}
If you can use boost, then here's an example of what I think you're trying to do ( although might work with std as well, I stick with boost personally ):
typedef boost::function<void ( MyClass&, const std::vector<std::string>& ) MyFunction;
std::map<std::string, MyFunction> dispatch_map;
namespace phx = boost::phoenix;
namespace an = boost::phoenix::arg_names;
dispatch_map.insert( std::make_pair( "someKey", phx::bind( &MyClass::CallBack, an::_1, phx::bind( &boost::lexical_cast< int, std::string >, phx::at( an::_2, 0 ) ) ) ) );
dispatch_map["someKey"]( someClass, std::vector< std::string >() );
However, as this sort of nesting quickly becomes fairly unreadable, it's usually best to either create a helper ( free function, or better yet a lazy function ) that does the conversion.
If I understand you correctly, you want to register void MyClass::Foo(int) and void MyClass::Bar(float), accepting that there will be a cast from std::string to int or float as appropriate.
To do this, you need a helper class:
class Argument {
std::string s;
Argument(std::string const& s) : s(s) { }
template<typename T> operator T { return boost::lexical_cast<T>(s); }
};
This makes it possible to wrap both void MyClass::Foo(int) and void MyClass::Bar(float) in a std::function<void(MyClass, Argument))>.
Interesting problme. This is indeen not trivial in C++, I wrote a self-contained implementation in C++11. It is possible to do the same in C++03 but the code would be (even) less readable.
#include <iostream>
#include <sstream>
#include <string>
#include <functional>
#include <vector>
#include <cassert>
#include <map>
using namespace std;
// string to target type conversion. Can replace with boost::lexical_cast.
template<class T> T fromString(const string& str)
{ stringstream s(str); T r; s >> r; return r; }
// recursive construction of function call with converted arguments
template<class... Types> struct Rec;
template<> struct Rec<> { // no parameters
template<class F> static void call
(const F& f, const vector<string>&, int) { f(); }
};
template<class Type> struct Rec< Type > { // one parameter
template<class F> static void call
(const F& f, const vector<string>& arg, int index) {
f(fromString<Type>(arg[index]));
}
};
template<class FirstType, class... NextTypes>
struct Rec< FirstType, NextTypes... > { // many parameters
template<class F> static void call
(const F& f, const vector<string>& arg, int index) {
Rec<NextTypes...>::call(
bind1st(f, fromString<FirstType>(arg[index])), // convert 1st param
arg,
index + 1
);
}
};
template<class... Types> void call // std::function call with strings
(const function<void(Types...)>& f, const vector<string>& args) {
assert(args.size() == sizeof...(Types));
Rec<Types...>::call(f, args, 0);
}
template<class... Types> void call // c function call with strings
(void (*f)(Types...), const vector<string>& args) {
call(function<void(Types...)>(f), args);
}
// transformas arbitrary function to take strings parameters
template<class F> function<void(const vector<string>&)> wrap(const F& f) {
return [&] (const vector<string>& args) -> void { call(f, args); };
}
// the dynamic dispatch table and registration routines
map<string, function<void(const vector<string>&)> > table;
template<class F> void registerFunc(const string& name, const F& f) {
table.insert(make_pair(name, wrap(f)));
}
#define smartRegister(F) registerFunc(#F, F)
// some dummy functions
void f(int x, float y) { cout << "f: " << x << ", " << y << endl; }
void g(float x) { cout << "g: " << x << endl; }
// demo to show it all works;)
int main() {
smartRegister(f);
smartRegister(g);
table["f"]({"1", "2.0"});
return 0;
}
Also, for performances, it's better to use unordered_map instead of map, and maybe avoid std::function overhead if you only have regular C functions. Of course this is only meaningful if dispatch time is significant compared to functions run-times.
No, C++ provides no facility for this to occur.