我的直觉是,这是不可能的,但我不是专家。 这就是我想做的事情:
#define KEY(i) #if (i == 0) KeyClassA(arg.fieldA)
#elif (i == 1) KeyClassB(arg.fieldB)
//...
#endif
//inside a function with given arg
for(int i = 0; i < N; i++) {
Data* data = array[i]->find(KEY(i));
//do things with data
}
该代码显然比C ++代码更伪代码,我个人认为这样的东西不会编译,但我的意图应该是明确的:根据相应的数据结构为find函数提供一个临时的类对象数组。也就是说,数组中的每个数据结构都需要不同的密钥匹配类。
宏观文本替换似乎是尝试实现这一目标的“最聪明”的方式,但我显然欢迎任何其他想法让这样的事情发挥作用。
答案 0 :(得分:4)
宏文本替换是您的问题的非解决方案,因为索引i
仅在运行时才知道。在编译之前甚至开始处理宏。
如果在编译时不知道N
,那么您将需要使用某些条件结构和可能的循环组合。如果KeyClass*
es的数量是固定的(似乎是这种情况),您可能会做这样的事情:
void Foo(int N, Array& array, const Bar& arg)
{
if(N > 3 || N <= 0) return;
Data* data = array[0]->find(KeyClassA(arg.fieldA));
// DoSomething(data);
if(N == 1) return;
data = array[1]->find(KeyClassB(arg.fieldB));
// DoSomething(data);
if(N == 2) return;
data = array[2]->find(KeyClassC(arg.fieldC));
// DoSomething(data);
}
将所有常用代码放在DoSomething()
函数中(最好使用更好的函数名),这样就不会重复N
的所有可能有效值。
如果在编译时知道N
,则可以简单地展开循环。
void Foo(Array& array, const Bar& arg)
{
Data* data = array[0]->find(KeyClassA(arg.fieldA));
// DoSomething(data);
data = array[1]->find(KeyClassB(arg.fieldB));
// DoSomething(data);
data = array[2]->find(KeyClassC(arg.fieldC));
// DoSomething(data);
}
如果你不想自己展开循环,你甚至可以使用模板元编程,虽然这对你正在做的事情可能有点过分:
// The basic idea using template specializations
template<int i>
struct GetKey;
template<>
struct GetKey<0>
{
KeyClassA From(const Bar& arg) { return KeyClassA(arg.fieldA); }
};
template<>
struct GetKey<1>
{
KeyClassB From(const Bar& arg) { return KeyClassB(arg.fieldB); }
};
template<>
struct GetKey<2>
{
KeyClassC From(const Bar& arg) { return KeyClassC(arg.fieldC); }
};
template<int i, int N>
struct Iterate
{
static void Body(Array& array, const Bar& arg)
{
Data* data = array[i]->find(GetKey<i>().From(arg));
// DoSomething(data);
Iterate<i+1, N>::Body(array, arg);
}
};
template<int N>
struct Iterate<N, N>
{
static void Body(Array& array, const Bar&) {}
};
void Foo(Array& array, const Bar& arg)
{
Iterate<0, 3>::Body(array, arg);
}
答案 1 :(得分:2)
在这种情况下,无论如何都不可能,因为i
不是编译时常量。 (不只是编译时常量,而是在预处理器阶段保持不变)
所以你必须使用普通的C ++ if语句来完成它。 (或开关)
基于我认为你想要做的事情,使用循环会使它变得比它需要的更复杂。只需将其全部写出来,就不需要任何循环或if语句。
array[0]->find(arg.fieldA);
array[1]->find(arg.fieldB);
...
(您似乎也没有对Data* data
)
编辑:有新信息。
在这种情况下,您可以将循环体放入函数调用中。像这样:
void loop_body(KeyClass &key, /* other parameters */ ){
Data* data = array[0]->find(key);
// Rest of the body
}
只需为每个字段调用它。
loop_body(arg.fieldA);
loop_body(arg.fieldB);
...
答案 2 :(得分:0)
你试过#define KEY(i) i?KeyClassB(arg.fieldB):KeyClassA(arg.fieldA)
答案 3 :(得分:0)
#define KEY(i) ((i) == 0 ? KeyClassA(arg.fieldA) : \
(i) == 1 ? KeyClassB(arg.fieldB) :\
...)
这是一个宏的事实真的不会给你带来什么;计算仍然必须在运行时完成,因为它取决于i
的值。
这将作为内联函数更有意义。