问题描述
我试图找到一个方法来遍历一个包变量模板参数列表。
现在和所有的迭代一样,你需要一些方法知道打包列表中有多少个参数,更重要的是如何从打包的参数列表中单独获取数据。
I'm trying to find a method to iterate over an a pack variadic template argument list.Now as with all iterations, you need some sort of method of knowing how many arguments are in the packed list, and more importantly how to individually get data from a packed argument list.
一般的想法是遍历列表,将所有类型为int的数据存储到向量中,将所有char *类型的数据存储到向量中,并将所有类型为float的数据存储到向量中。在这个过程中,还需要一个独立的向量来存储参数进入的顺序的单个字符。例如,当你push_back(a_float),你也做一个push_back('f'),它只是存储一个单独的char来知道数据的顺序。我也可以使用std :: string这里,只需使用+ =。该向量只是作为一个例子。
The general idea is to iterate over the list, store all data of type int into a vector, store all data of type char* into a vector, and store all data of type float, into a vector. During this process there also needs to be a seperate vector that stores individual chars of what order the arguments went in. As an example, when you push_back(a_float), you're also doing a push_back('f') which is simply storing an individual char to know the order of the data. I could also use a std::string here and simply use +=. The vector was just used as an example.
现在的东西设计的方式是使用宏构建函数本身,尽管邪恶的意图,它是必需的,因为这是一个实验。因此,实际上不可能使用递归调用,因为将包含所有这些的实际实现将在编译时扩展;你不能重现一个宏。
Now the way the thing is designed is the function itself is constructed using a macro, despite the evil intentions, it's required, as this is an experiment. So it's literally impossible to use a recursive call, since the actual implementation that will house all this will be expanded at compile time; and you cannot recruse a macro.
尽管所有可能的尝试,我仍然坚持想办法如何做到这一点。所以,我使用一个更复杂的方法,涉及到构建一个类型,并将该类型传递到varadic模板,将其扩展到一个向量,然后简单地迭代。但是我不想像下面这样调用函数:
Despite all possible attempts, I'm still stuck at figuring out how to actually do this. So instead I'm using a more convoluted method that involves constructing a type, and passing that type into the varadic template, expanding it inside a vector and then simply iterating that. However I do not want to have to call the function like:
foo(arg(1), arg(2.0f), arg("three");
所以真正的问题是如何没有这样?你们更好地理解代码实际上在做什么,我已经粘贴了我目前使用的乐观方法。
So the real question is how can I do without such? To give you guys a better understanding of what the code is actually doing, I've pasted the optimistic approach that I'm currently using.
struct any {
void do_i(int e) { INT = e; }
void do_f(float e) { FLOAT = e; }
void do_s(char* e) { STRING = e; }
int INT;
float FLOAT;
char *STRING;
};
template<typename T> struct get { T operator()(const any& t) { return T(); } };
template<> struct get<int> { int operator()(const any& t) { return t.INT; } };
template<> struct get<float> { float operator()(const any& t) { return t.FLOAT; } };
template<> struct get<char*> { char* operator()(const any& t) { return t.STRING; } };
#define def(name) \
template<typename... T> \
auto name (T... argv) -> any { \
std::initializer_list<any> argin = { argv... }; \
std::vector<any> args = argin;
#define get(name,T) get<T>()(args[name])
#define end }
any arg(int a) { any arg; arg.INT = a; return arg; }
any arg(float f) { any arg; arg.FLOAT = f; return arg; }
any arg(char* s) { any arg; arg.STRING = s; return arg; }
我知道这很讨厌,但它是一个纯实验,不会用于生产代码。这纯粹是一个想法。这可能是一个更好的方法。但是一个如何使用这个系统的例子:
I know this is nasty, however it's a pure experiment, and will not be used in production code. It's purely an idea. It could probably be done a better way. But an example of how you would use this system:
def(foo)
int data = get(0, int);
std::cout << data << std::endl;
end
看起来很像python。它也工作,但唯一的问题是如何调用此函数。
一个快速示例:
looks a lot like python. it works too, but the only problem is how you call this function.Heres a quick example:
foo(arg(1000));
我需要构造一个新的任何类型,这是高度审美,但不是说这些宏不是。除此之外,我只想做选择:
foo(1000);
I'm required to construct a new any type, which is highly aesthetic, but thats not to say those macros are not either. Aside the point, I just want to the option of doing: foo(1000);
我知道这可以做,我只需要一些迭代方法,或者更重要的是一些std :: get方法用于打包可变参数模板参数列表。我确定可以做。
I know it can be done, I just need some sort of iteration method, or more importantly some std::get method for packed variadic template argument lists. Which I'm sure can be done.
还要注意,我很清楚,这不是完全类型友好,因为我只支持int,float ,char *,这和我很好。我不需要任何其他,我将添加检查使用type_traits验证传递的参数是否确实是正确的,如果数据不正确,产生编译时错误。这完全不是一个问题。我也不需要支持这些POD类型的任何东西。
Also to note, I'm well aware that this is not exactly type friendly, as I'm only supporting int,float,char* and thats okay with me. I'm not requiring anything else, and I'll add checks to use type_traits to validate that the arguments passed are indeed the correct ones to produce a compile time error if data is incorrect. This is purely not an issue. I also don't need support for anything other then these POD types.
如果我能得到一些建设性的帮助,反对关于我纯粹不合逻辑的和愚蠢的使用宏和POD类型。我很清楚代码是多么脆弱和破碎。这是merley的实验,我可以稍后纠正非POD数据的问题,并使其更加类型安全和可用。
It would be highly apprecaited if I could get some constructive help, opposed to arguments about my purely illogical and stupid use of macros and POD only types. I'm well aware of how fragile and broken the code is. This is merley an experiment, and I can later rectify issues with non-POD data, and make it more type-safe and useable.
感谢您的谅解,我
推荐答案
如果要将参数包装到任何
,可以使用以下设置。我还使任何
类更可用,虽然它在技术上不是一个任何
类。
If you want to wrap arguments to any
, you can use the following setup. I also made the any
class a bit more usable, although it isn't technically an any
class.
#include <vector>
#include <iostream>
struct any {
enum type {Int, Float, String};
any(int e) { m_data.INT = e; m_type = Int;}
any(float e) { m_data.FLOAT = e; m_type = Float;}
any(char* e) { m_data.STRING = e; m_type = String;}
type get_type() const { return m_type; }
int get_int() const { return m_data.INT; }
float get_float() const { return m_data.FLOAT; }
char* get_string() const { return m_data.STRING; }
private:
type m_type;
union {
int INT;
float FLOAT;
char *STRING;
} m_data;
};
template <class ...Args>
void foo_imp(const Args&... args)
{
std::vector<any> vec = {args...};
for (unsigned i = 0; i < vec.size(); ++i) {
switch (vec[i].get_type()) {
case any::Int: std::cout << vec[i].get_int() << '\n'; break;
case any::Float: std::cout << vec[i].get_float() << '\n'; break;
case any::String: std::cout << vec[i].get_string() << '\n'; break;
}
}
}
template <class ...Args>
void foo(Args... args)
{
foo_imp(any(args)...); //pass each arg to any constructor, and call foo_imp with resulting any objects
}
int main()
{
char s[] = "Hello";
foo(1, 3.4f, s);
}
然而,可以编写函数来访问可变参数模板中的第n个参数函数,并对每个参数应用一个函数,这可能是一个更好的方式来做任何你想要实现的。
It is however possible to write functions to access the nth argument in a variadic template function and to apply a function to each argument, which might be a better way of doing whatever you want to achieve.
这篇关于如何迭代一个打包的可变参数模板参数列表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!