以下代码在g ++ -std = c ++ 11编译器的编译中失败。
# include<iostream>
# include<vector>
using namespace std;
# define stlf(x) x.begin(), x.end()
# define repf(it, a, b) for(auto it = a ; it != b ; ++it)
/*
// Also, following alternative fails
# define repf(it, a, b) for(auto it = a ; it != b ; ++it)
# define stlf(x) x.begin(), x.end()
*/
typedef vector<int > vi;
# define pd(x) printf("%d", x);
int main(void){
vi arr(10, -1);
repf(arr, stlf(arr))
pd(arr[i]);
return 0;
}
1。为什么会这样?
2。 C ++预处理器实现者的实现问题是什么,他们避免了这个功能?
3. 我怎样才能使用这样的快捷方式?
答案 0 :(得分:5)
你的两个选择是相同的。定义宏的顺序与它们的扩展无关;它只与扩张时的定义有关。
为什么会这样?
您使用两个参数调用宏repf
,但它需要三个参数。这是一个错误,简单明了,因此预处理失败。
C ++预处理器实现者的实现问题是什么,他们避免了这个功能?
我认为你在这里做出了无根据的假设。问题不在于预处理器&#34;缺乏&#34;一些&#34;功能&#34 ;;你对预处理器如何工作的期望是错误的。
据推测,您希望预处理器执行以下操作:
repf(arr, stlf(arr))
repf(arr, arr.begin(), arr.end())
for(auto it = arr.begin() ; it != arr.end() ; ++it)
...从第1步到第2步,stlf(arr)
得到扩展;然后将其扩展放入repf
的调用中,然后在第3步扩展。
问题是,这不是预处理器的工作方式。鉴于示例已被破坏,我无法正确说明这些步骤,因此我们假设我们这样做是为了说明目的:
#define FOO(X, Y) BAR(X, Y)
#define BAR(X,Y,Z) x is X y is Y z is Z
#define ACOMMAB A, B
FOO(ACOMMAB, C)
最后一行扩展为x is A y is B c is Z
,它更像是这样:
FOO(ACOMMAB, C)
BAR(ACOMMAB, C)
BAR(A, B, C)
x is A y is B c is Z
请注意,内部宏不会先扩展;相反,外部宏确实如此。另请注意,此示例注入逗号;所以注入一个逗号肯定是你可以实际做的事情,我认为这是&#34;功能&#34;你提到这是避免的。
我怎样才能使用这样的快捷方式?
鉴于预处理器并不像您认为的那样工作,您可能不想使用它来执行您认为要用它做的事情......即使是速度编码也是如此。 stlf
很乐意为函数调用构建两个参数,但宏不是函数。似乎是你最好的选择。
答案 1 :(得分:2)
问题是,正如H Walters所指出的那样, order 中的宏做事情
请注意,上面有两个地方可以展开其他宏,因此虽然订单可能对您想要做的事情有误,但您可以通过添加额外的宏调用来实现目标。发生在你想要的时候。例如,如果您有一个宏
#define expand(...) __VA_ARGS__
什么都不做(只需要一个或多个参数并在其中扩展宏),您可以使用它在正确的位置获得额外的宏扩展:
expand( repf expand((arr, stlf(arr))) )
将展开到您想要的for(auto it = arr.begin() ; it != arr.end() ; ++it)
这可能看起来很笨拙,但你可以将调用包装在另一个重新聚焦的宏中:
# define stlf(x) x.begin(), x.end()
# define expand(...) __VA_ARGS__
# define repf(...) expand(repf2 expand((__VA_ARGS__)))
# define repf2(it, a, b) for(auto it = a ; it != b ; ++it)
现在repf(arr, stlf(arr))
扩展了你想要的方式。
答案 2 :(得分:1)
repf
期待3个参数而你只传递2.你不能使用另一个宏的扩展结果(stlf
)作为参数(对于另一个宏)。预处理器/编译器不是这样设计的。
我不反对宏(在许多情况下它们非常有用),但对于这个简单的情况,你不能使用宏。它使您的程序难以阅读,维护和调试。避免!
理想情况下,你应该使用基于范围的循环(没有宏):
for(int a : arr) ...
答案 3 :(得分:0)
它应该是这样的:
define repf(it, a) for(auto it = std::begin(a) ; it != std::end(a) ; ++it)
但是你为什么要使用宏呢?