定义宏改进特定函数的语法
Defining macro improving syntax of specific function
我创建了一个函数声明为:
template <typename Container, typename Task>
void parallel_for_each(Container &container, Task task,
unsigned number_of_threads = std::thread::hardware_concurrency())
不难猜出它应该做什么。我想创建一个宏来简化此函数的语法并使其语法 "loop-like"。我想出了一个主意:
#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;
});
报错
macro "pforeach" requires 3 arguments, but only 2 given
你知道如何编写甚至允许 "nicer" 语法的宏吗?为什么 "in" 在我的代码中不代表逗号?
没有宏语言。宏由 C/C++ 预处理器处理。预处理器的实现可能会有所不同。
大多数预处理器都希望您传递准确数量的参数。我发现 GNU 预处理器对参数的检查不太严格,这允许一种可变参数列表。但一般来说,宏不会帮助您完成任务。
我建议用函数而不是宏来编写简短的语句。内联函数与宏一样快速和简短,但类型安全。
此外,该函数允许默认参数值。所以你可以跳过一些东西。
Why "in" doesn't stand for comma in my code?
因为替换是在 宏参数确定后执行的。引用标准草案 N3797,§ 16.3.1 参数替换:
After the arguments for the invocation of a function-like macro have been identified, argument substitution takes place. ... Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file; no other preprocessing tokens
are available.
因此预处理器将 pforeach(double &element in vec, {})
识别为具有两个参数的类似函数的宏调用:
- 首先由标记
double
、&
、in
和 vec
组成,并绑定到参数 Z
- 第二个由标记
{
和 }
组成并绑定到参数 X
你显然错过了争论Y
Do you have any idea how to write a macro allowing even "nicer" syntax?
这很难回答,这是品味问题。不管怎样,C++ 有丰富的运算符重载修补语法的能力,但你不能用它来构建 DSL,所以最好使用默认语法,它不是那么难看(也更容易阅读):
parallel_for_each(vec, [](double& el){ el *= 2; })
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
定义为,
不会有好下场!
添加 "nicer" 语法的想法:
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.
虽然有几个缺点。我只会坚持你目前所拥有的。
尝试改进@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
宏。欢迎任何反馈!
我创建了一个函数声明为:
template <typename Container, typename Task>
void parallel_for_each(Container &container, Task task,
unsigned number_of_threads = std::thread::hardware_concurrency())
不难猜出它应该做什么。我想创建一个宏来简化此函数的语法并使其语法 "loop-like"。我想出了一个主意:
#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;
});
报错
macro "pforeach" requires 3 arguments, but only 2 given
你知道如何编写甚至允许 "nicer" 语法的宏吗?为什么 "in" 在我的代码中不代表逗号?
没有宏语言。宏由 C/C++ 预处理器处理。预处理器的实现可能会有所不同。
大多数预处理器都希望您传递准确数量的参数。我发现 GNU 预处理器对参数的检查不太严格,这允许一种可变参数列表。但一般来说,宏不会帮助您完成任务。
我建议用函数而不是宏来编写简短的语句。内联函数与宏一样快速和简短,但类型安全。 此外,该函数允许默认参数值。所以你可以跳过一些东西。
Why "in" doesn't stand for comma in my code?
因为替换是在 宏参数确定后执行的。引用标准草案 N3797,§ 16.3.1 参数替换:
After the arguments for the invocation of a function-like macro have been identified, argument substitution takes place. ... Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file; no other preprocessing tokens are available.
因此预处理器将 pforeach(double &element in vec, {})
识别为具有两个参数的类似函数的宏调用:
- 首先由标记
double
、&
、in
和vec
组成,并绑定到参数Z
- 第二个由标记
{
和}
组成并绑定到参数X
你显然错过了争论Y
Do you have any idea how to write a macro allowing even "nicer" syntax?
这很难回答,这是品味问题。不管怎样,C++ 有丰富的运算符重载修补语法的能力,但你不能用它来构建 DSL,所以最好使用默认语法,它不是那么难看(也更容易阅读):
parallel_for_each(vec, [](double& el){ el *= 2; })
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
定义为,
不会有好下场!
添加 "nicer" 语法的想法:
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.
虽然有几个缺点。我只会坚持你目前所拥有的。
尝试改进@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
宏。欢迎任何反馈!