Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variadic Tuple Order changes after Unpacking depending on Datatypes

The code should call back a function by extracting arguments from a string. However, the order changes as follows: (Visual Studio 2013 AND 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

Edit : It works properly in gcc and is a MS Visual C++ compiler bug - Tested for VS2013 and VS2015. Does anyone knows a work around ? (Maybe using some C++14 feature? )

Edit2: I solved it adding indices to the parameters and removed the tuple too http://cpp.sh/9jc5

Here the sample:

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);
}

And the complete code:

#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 ------------------

References used

How do I expand a tuple into variadic template function's arguments?

build tuple using variadic templates

like image 680
Marco Polo Avatar asked Jan 24 '26 13:01

Marco Polo


1 Answers

Change:

template <typename... Args>
std::tuple<Args...> parse(std::istream& is)
{
    return std::make_tuple(read<Args>(is)...);
}

into:

template <typename... Args>
std::tuple<Args...> parse(std::istream& is)
{
    return std::tuple<Args...>{ read<Args>(is)... };
}

Otherwise, the order in which function read is called is unspecified.

like image 172
Piotr Skotnicki Avatar answered Jan 27 '26 02:01

Piotr Skotnicki



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!