是否可以在C预处理器中进行部分宏应用/ currying?

时间:2013-02-06 17:53:57

标签: c c-preprocessor currying partial-application

作为问题的一个示例,有没有办法在以下代码中实现宏partialconcat

#define apply(f, x) f(x)

apply(partialconcat(he),llo) //should produce hello

编辑:

这是另一个例子,给定一个FOR_EACH可变参数宏(参见this answer中另一个问题的示例实现)。

说我想在几个对象上调用成员, 可能在另一个宏中用于更大的目的。 我想要一个宏callAmber,其行为如下:

FOR_EACH(callMember(someMemberFunction), a, b, c);

产生

a.someMemberFunction(); b.someMemberFunction(); c.someMemberFunction();

这需要callMember(someMember)来生成一个行为类似于

的宏
#define callMember_someMember(o) o.someMember()

3 个答案:

答案 0 :(得分:5)

使用Vesa Karvonen令人难以置信的“订购”语言/库,您可以使用预处理器实现所需的结果http://rosettacode.org/wiki/Order

这可以通过在预处理器本身的之上实现第二个高级语言来实现,并支持currying和一流宏等等。这是非常繁重的,但非常重要的Order代码需要很长时间才能编译,因为CPP并不是以这种方式设计的,而且大多数C编译器都无法处理它。它也非常脆弱:输入代码中的错误往往会产生难以理解的乱码输出。

但是,是的,它可以完成,并在一个预处理器传递中完成。它只是一个很多比你想象的更复杂。

答案 1 :(得分:2)

使用更高阶的宏:

#define OBJECT_LIST(V) \
    V(a) \
    V(b) \
    V(c)

#define MEMBER_CALL(X) \
    X.some_func();


OBJECT_LIST(MEMBER_CALL)

<强>输出

$ g++ -E main.cc
# 1 "main.cc"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "main.cc"
# 10 "main.cc"
a.some_func(); b.some_func(); c.some_func();

因为它是一个编译时循环,所以很难进行curry。 OBJECT_LIST宏定义了允许此列表的每个用户进行咖喱的参数数量。 (默认)函数调用参数是define的一部分。您可以自由选择不使用默认提供的参数或自己使用常量值。我无法找到减少预处理器中参数数量的正确方法。这一事实限制了这种技术的普遍性。

#define OBJECT_LIST(V) \
    V(a, 1,2,3) \
    V(b, 4,5,6)

#define MEMBER_CALL(X, A1, A2, A3) \
    X.somefunc(A1, A2, A3);

#define CURRY_CALL(X, A1, A2, A3) \
    X.somefunc(A1, 2, 2);

#define NO_CURRY_CALL(X, A1, A2, A3) \
    X.xomefunc(A1);


OBJECT_LIST(MEMBER_CALL)
OBJECT_LIST(CURRY_CALL)
OBJECT_LIST(NO_CURRY_CALL)

<强>输出:

# 1 "main2.cc"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "main2.cc"
# 12 "main2.cc"
a.somefunc(1, 2, 3); b.somefunc(4, 5, 6);
a.somefunc(1, 2, 2); b.somefunc(4, 2, 2);
a.somefunc(1); b.somefunc(4);

答案 2 :(得分:1)

C预处理器“仅”是一个简单的文本处理器。特别是,一个宏不能定义另一个宏;你无法通过扩展宏来创建#define

我认为这意味着问题的最后两行:

  

这需要callMember(someMember)来生成一个行为类似于

的宏      

#define callMember_someMember(o) o.someMember()

使用C预处理器的单个应用程序无法实现

(在一般情况下,您需要将预处理器应用任意次数,具体取决于宏的定义方式。)