【发布时间】:2011-11-06 00:49:35
【问题描述】:
我正在尝试找到一种方法来迭代一个包可变参数模板参数列表。 现在与所有迭代一样,您需要某种方法来了解打包列表中有多少参数,更重要的是如何从打包参数列表中单独获取数据。
总体思路是遍历列表,将所有int类型的数据存入vector,将char*类型的所有数据存入vector,将float类型的所有数据存入vector。在这个过程中,还需要一个单独的向量来存储参数输入顺序的各个字符。例如,当你 push_back(a_float) 时,你也在做一个 push_back('f'),它只是存储一个单独的字符来了解数据的顺序。我也可以在这里使用 std::string 并简单地使用 +=。向量只是作为一个例子。
现在这个东西的设计方式是使用宏构造函数本身,尽管有恶意,但它是必需的,因为这是一个实验。所以实际上不可能使用递归调用,因为包含所有这些的实际实现将在编译时扩展;并且您不能重新生成宏。
尽管进行了所有可能的尝试,但我仍然坚持弄清楚如何真正做到这一点。因此,我使用了一种更复杂的方法,该方法涉及构造一个类型,并将该类型传递给 varadic 模板,将其扩展为一个向量,然后简单地对其进行迭代。但是我不想像这样调用函数:
foo(arg(1), arg(2.0f), arg("three");
所以真正的问题是,如果没有这些,我该怎么办?为了让你们更好地了解代码实际在做什么,我粘贴了我目前使用的乐观方法。
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; }
我知道这很糟糕,但这是一个纯粹的实验,不会用于生产代码。这纯粹是一个想法。它可能可以做得更好。但是,您将如何使用此系统的示例:
def(foo)
int data = get(0, int);
std::cout << data << std::endl;
end
看起来很像python。它也可以,但唯一的问题是你如何调用这个函数。 下面是一个简单的例子:
foo(arg(1000));
我需要构造一个新的 any 类型,它非常美观,但这并不是说这些宏也不是。顺便说一句,我只想选择这样做: 富(1000);
我知道可以做到,我只需要某种迭代方法,或者更重要的是一些用于打包可变参数模板参数列表的 std::get 方法。我确信可以做到。
另外需要注意的是,我很清楚这并不完全是类型友好的,因为我只支持 int、float、char* ,这对我来说没问题。我不需要其他任何东西,我将添加检查以使用 type_traits 来验证传递的参数确实是正确的,以便在数据不正确时产生编译时错误。这完全不是问题。除了这些 POD 类型之外,我也不需要任何支持。
如果我能得到一些建设性的帮助,我将不胜感激,反对关于我纯粹不合逻辑和愚蠢地使用宏和仅 POD 类型的争论。我很清楚代码是多么脆弱和破碎。这是 merley 的一项实验,我稍后可以纠正非 POD 数据的问题,并使其更加类型安全和可用。
感谢您的理解,我期待提供帮助。
【问题讨论】:
-
看起来有点像你可以改用
boost::variant<int, float, std::string>。但是,这将只允许一次为每个“任何”存储一个值,并提供检查存储值类型的方法。 -
我不想使用 boost。尽管其他人似乎喜欢它提供的大量支持,但我只是试图坚持标准库中支持的内容。
标签: c++ c++11 variadic-templates