我创建了一个声明为:
的函数template <typename Container, typename Task>
void parallel_for_each(Container &container, Task task,
unsigned number_of_threads = std::thread::hardware_concurrency())
猜测它应该做什么并不难。我想创建一个宏来简化这个函数的语法,并使其语法“循环”。我想出了一个主意:
#define in ,
#define pforeach(Z,X,Y) parallel_for_each(X,[](Z)->void{Y;})
用法为:
pforeach(double &element, vec,
{
element *= 2;
});
按预期工作,但这一个:
pforeach(double &element in vec,
{
element *= 2;
element /= 2;
});
给出错误
宏“pforeach”需要3个参数,但只有2个
您是否知道如何编写一个允许“更好”语法的宏?为什么“in”不代表我的代码中的逗号?
答案 0 :(得分:4)
in
未被替换的原因是它出现在类函数宏的参数内,但是要替换它,这些参数必须首先传播到另一个宏:尝试
#define in ,
#define pforeach_(Z,X,Y) parallel_for_each(X,[](Z)->void{Y;})
#define pforeach(Z,X,Y) pforeach_(Z,X,Y)
注意:将in
定义为,
并不会结束!
添加“更好”语法的想法:
template <typename Container>
struct Helper {
Container&& c;
template <typename Arg>
void operator=(Arg&& arg) {
parallel_for_each(std::forward<Container>(c), std::forward<Arg>(arg));
}
};
#define CONCAT_(a,b) a##b
#define CONCAT(a,b) CONCAT_(a,b)
// Easier with Boost.PP
#define DEC_1 0
#define DEC_2 1
#define DEC_3 2
#define DEC_4 3
#define DEC_5 4
#define DEC_6 5
#define DEC_7 6
#define DEC_8 7
#define DEC(i) CONCAT(DEC_,i)
#define pforeach(Z, ...) \
Helper<decltype((__VA_ARGS__))> CONCAT(_unused_obj, __COUNTER__){__VA_ARGS__}; \
CONCAT(_unused_obj, DEC(__COUNTER__))=[](Z)
可用作
int a[] = {1, 2, 3};
pforeach(int i, a) {
std::cout << i << ", ";
};
pforeach(int i, std::vector<int>{1, 2, 3}) {
std::cout << -i << ", ";
};
Demo。
但有几个缺点。我坚持你到目前为止所拥有的。
答案 1 :(得分:1)
为什么“in”不代表我的代码中的逗号?
因为在确定宏参数后执行了替换。引用标准草案N3797,§16.3.1参数替换:
在识别出类似函数的宏的调用参数之后,发生参数替换。 ...在被替换之前,每个参数的预处理标记都被完全宏替换,好像它们形成了预处理文件的其余部分;没有其他预处理令牌 可用。
因此预处理器将pforeach(double &element in vec, {})
标识为具有两个参数的类函数宏调用:
double
,&
,in
和vec
并绑定到参数Z
{
和}
并绑定到参数X
你显然错过了论据Y
您是否知道如何编写一个允许“更好”语法的宏?
很难回答,这是味道的问题。无论如何,C ++具有丰富的修补语法与运算符重载的能力,但你不能用它来构建DSL,所以最好使用默认语法,它不是那么难看(并且也易于阅读):
parallel_for_each(vec, [](double& el){ el *= 2; })
答案 2 :(得分:0)
没有宏的langugae。宏由C / C ++预处理器处理。预处理器的实现可能会有所不同。
大多数预处理器都希望您传递确切数量的参数。我发现GNU预处理器对参数的检查不太严格,它允许一种可变参数列表。但总的来说,宏不会帮助你完成任务。
我建议在函数中编写short语句而不是宏。内联函数与宏一样快和短,但类型安全。 此外,该功能允许默认参数值。所以你可以跳过一些东西。
答案 3 :(得分:0)
试图改进@Columbo的想法:
template <typename Container>
struct __pforeach__helper {
Container &&c;
template <typename Arg>
void operator=(Arg&& arg) {
parallel_for_each(std::forward<Container>(c), std::forward<Arg>(arg));
}
};
//additional helper function
template <typename Container>
__pforeach__helper<Container> __create__pforeach__helper(Container &&c)
{
return __pforeach__helper<Container>(__pforeach__helper<Container>{c});
}
#define pforeach(Z,C) \
__create__pforeach__helper(C)=[](Z)
它不依赖于__COUNTER__
,也不需要定义DEC_x
个宏。欢迎任何反馈!