Код должен вызывать функцию, извлекая аргументы из строки.
Однако порядок изменяется следующим образом: (Visual Studio 2013 И 2015! Express)
«1 2 3 4» int, double, string, int -> 3 2 4 1
«1 2 3 4» int, double, float, int -> 4 3 2 1
Редактировать: Это правильно работает в gcc и является Ошибка компилятора MS Visual C ++ — Протестировано для VS2013 и VS2015. Кто-нибудь знает обходной путь? (Может быть, с использованием какой-либо функции C ++ 14?)
Edit2: я решил, добавив индексы к параметрам и удалил кортеж тоже
http://cpp.sh/9jc5
Вот образец:
void one(int i, double d, string s, int ii)
{
std::cout << "function one(" << i << ", " << d << ", " << s << ", " << ii << ");\n";
}
int main()
{
RegisterRPC<int, double, string, int>("test1", one);
DataSource* data=new DataSource("1 2 3 4");
functionarray["test1"](data);
system("pause");
return 0;
}
И полный код:
#include <stdlib.h>
#include <functional>
#include <tuple>
#include <map>
#include <iostream>
#include <istream>
#include <sstream>
#include <string>
// ------------- UTILITY---------------
template<int...> struct index_tuple{};
template<int I, typename IndexTuple, typename... Types>
struct make_indexes_impl;
template<int I, int... Indexes, typename T, typename ... Types>
struct make_indexes_impl<I, index_tuple<Indexes...>, T, Types...>
{
typedef typename make_indexes_impl<I + 1, index_tuple<Indexes..., I>, Types...>::type type;
};
template<int I, int... Indexes>
struct make_indexes_impl<I, index_tuple<Indexes...> >
{
typedef index_tuple<Indexes...> type;
};
template<typename ... Types>
struct make_indexes : make_indexes_impl<0, index_tuple<>, Types...>
{};
// ----------UNPACK TUPLE AND APPLY TO FUNCTION ---------
using namespace std;
template<class Ret, class... Args, int... Indexes >
Ret apply_helper(Ret(*pf)(Args...), index_tuple< Indexes... >, tuple<Args...>&& tup)
{
return pf(forward<Args>(get<Indexes>(tup))...);
}
template<class Ret, class ... Args>
Ret apply(Ret(*pf)(Args...), const tuple<Args...>& tup)
{
return apply_helper(pf, typename make_indexes<Args...>::type(), tuple<Args...>(tup));
}
template<class Ret, class ... Args>
Ret apply(Ret(*pf)(Args...), tuple<Args...>&& tup)
{
return apply_helper(pf, typename make_indexes<Args...>::type(), forward<tuple<Args...>>(tup));
}
// --- make tuple ---
template <typename T> T read(std::istream& is)
{
T t; is >> t; cout << t << endl; return t;
}
template <typename... Args>
std::tuple<Args...> parse(std::istream& is)
{
return std::make_tuple(read<Args>(is)...);
}
template <typename... Args>
std::tuple<Args...> parse(const std::string& str)
{
std::istringstream ips(str);
return parse<Args...>(ips);
};
// ---- RPC stuff
class DataSource
{
std::string data;
public:
DataSource(std::string s) { data = s; };
template<class...Ts> std::tuple<Ts...> get() { return parse<Ts...>(data); };
};
std::map<std::string, std::function<void(DataSource*)> > functionarray;
template<typename... Args, class F>
void RegisterRPC(std::string name, F f) {
functionarray[name] = [f](DataSource* data){apply(f, data->get<Args...>()); };
}
// --------------------- TEST ------------------
void one(int i, double d, string s, int ii)
{
std::cout << "function one(" << i << ", " << d << ", " << s << ", " << ii << ");\n";
}
int main()
{
RegisterRPC<int, double, string, int>("test1", one);
DataSource* data=new DataSource("1 2 3 4");
functionarray["test1"](data);
system("pause");
return 0;
}
// --------------------- TEST ------------------
Использованные ссылки
Как развернуть кортеж в аргументы функции шаблона переменной?
создать кортеж с использованием шаблонов с переменным числом аргументов
Изменить:
template <typename... Args>
std::tuple<Args...> parse(std::istream& is)
{
return std::make_tuple(read<Args>(is)...);
}
в:
template <typename... Args>
std::tuple<Args...> parse(std::istream& is)
{
return std::tuple<Args...>{ read<Args>(is)... };
}
В противном случае порядок, в котором функция read
называется не указано.
Здесь фиксированная версия с использованием индексов — на случай, если кому-то будет интересно.
#include <tuple>
#include <iostream>
#include <strstream>
#include <istream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <functional>
// ------------- UTILITY---------------
template<int...> struct index_tuple{};
template<int I, typename IndexTuple, typename... Types>
struct make_indexes_impl;
template<int I, int... Indexes, typename T, typename ... Types>
struct make_indexes_impl<I, index_tuple<Indexes...>, T, Types...>
{
typedef typename make_indexes_impl<I + 1, index_tuple<Indexes..., I>, Types...>::type type;
};
template<int I, int... Indexes>
struct make_indexes_impl<I, index_tuple<Indexes...> >
{
typedef index_tuple<Indexes...> type;
};
template<typename ... Types>
struct make_indexes : make_indexes_impl<0, index_tuple<>, Types...>{};
using namespace std;
// --- process single datatype ---
struct anyT
{
anyT(int e) { cout << " int" << endl; }
anyT(float e) { cout << " float" << endl; }
anyT(string e) { cout << " string" << endl; }
anyT(double e) { cout << " double" << endl; }
};
template <typename T> T read_from(int index, std::vector<string> &list)
{
std::istringstream is(list[index]);
T t; is >> t; cout << "index " << index << " val " << t; anyT a(t); return t;
}
// ---- RPC stuff ----
std::map<std::string, std::function<void(string*)> > functionarray;
template<typename... Args, class F, int... Is>
void RegisterRPC_index(std::string name, F f, index_tuple< Is... >) {
functionarray[name] = [f](string* data)
{
const int n = sizeof...(Args);
cout << n << " args\n";
std::vector<string> list;
std::istringstream ips(*data);
for (int i = 0; i < n;i++)
{
string s;
ips >> s;
list.push_back(s);
}
f(read_from<Args>(Is, list)...);
};
}
template<typename... Args, class F>
void RegisterRPC(std::string name, F f)
{
RegisterRPC_index<Args...>(name,f,typename make_indexes<Args...>::type());
}
// --------------------- TEST ------------------
void one(int i, double d, string s, int ii)
{
std::cout << "function one(" << i << ", " << d << ", " << s << ", " << ii << ");\n";
}
int main()
{
RegisterRPC<int, double, string, int>("test1", one);
string* data=new string("1 2.2 hello3 4");
functionarray["test1"](data);
return 0;
}