【问题标题】:Variadic Tuple Order changes after Unpacking depending on Datatypes解包后可变元组顺序根据数据类型更改
【发布时间】:2015-10-02 19:20:22
【问题描述】:

代码应该通过从字符串中提取参数来回调函数。 但是,顺序更改如下:(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

编辑:它works properly in gccMS Visual C++ compiler bug - 已针对 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);
}

以及完整的代码:

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

参考文献

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

build tuple using variadic templates

【问题讨论】:

  • 您希望如何使用data-&gt;get&lt;Args...&gt;() 区分重复的类型参数?
  • @AndreyNasonov:嗯,我希望编译器能自动解决这个问题..
  • 不,它做不到。调用data-&gt;get&lt;int&gt;() 会产生什么结果?
  • @AndreyNasonov 为了安全起见,需要以某种方式使用 get(tup) 助手?
  • 我认为是的,您应该使用索引而不是类型名称

标签: c++ templates tuples c++14 variadic-templates


【解决方案1】:

变化:

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的调用顺序未指定。

【讨论】:

  • 感谢您的快速回答。 "one(int, double, string, int)" 的输出仍然是函数 one(3, 2, 4, 1),而调用 read 的顺序是正确的 1 2 3 4。
  • @MarcoPolo 不可能
  • @MarcoPolo 我猜你看到的是this MSVC bug
  • @ildjarn 如果不持久,就什么都不是!
  • @PiotrSkotnicki 你知道如何解决这个问题吗?也许使用 C++14 ?我确认 VS2015 有同样的错误。
【解决方案2】:

这里是使用索引的固定版本 - 以防有人感兴趣。

http://cpp.sh/7mgo

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

【讨论】:

    猜你喜欢
    • 2020-08-06
    • 1970-01-01
    • 1970-01-01
    • 2017-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多