定义宏以改进特定函数的语法

Defining macro improving syntax of specific function

本文关键字:函数 语法 定义      更新时间:2023-10-16

我创建了一个声明为:的函数

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"在我的代码中不代表逗号?

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 << ", ";
};

演示
不过有几个缺点。到目前为止,我会坚持你所拥有的。

为什么"in"在我的代码中不代表逗号?

因为该替换是在确定宏参数后执行的。引用标准草案N3797,§16.3.1论点替代:

在确定了调用类似函数的宏的参数后,将进行参数替换。。。在被替换之前,每个参数的预处理标记都被完全宏替换,就好像它们构成了预处理文件的其余部分一样;没有其他预处理令牌可用。

因此,预处理器将pforeach(double &element in vec, {})识别为一个类似函数的宏调用,具有两个参数:

  1. 第一个由标记double&invec组成,并绑定到参数Z
  2. 第二个由标记{}组成,并绑定到参数X

您显然错过了参数Y

你知道如何编写一个允许"更好"语法的宏吗?

很难回答,这是品味问题。无论如何,C++有丰富的能力用运算符重载修补语法,但你不能用它来构建DSL,所以最好使用默认语法,它没有那么难看(也让它很容易阅读):

parallel_for_each(vec, [](double& el){ el *= 2; })

没有宏语言。宏由C/C++预处理器处理。预处理器的实现方式可能有所不同。

大多数预处理器都期望您传递确切数量的参数。我发现GNU预处理器对参数的检查不那么严格,这允许一种可变列表。但总的来说,宏对你的任务没有帮助。

我建议在函数中而不是在宏中编写简短的语句。内联函数与宏一样快速、简短,但类型安全。此外,该功能允许默认参数值。所以你可以跳过一些东西。

试图改进@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宏。欢迎任何反馈!