我有两个宏,FOO2并且FOO3:
#define FOO2(x,y) ...
#define FOO3(x,y,z) ...
Run Code Online (Sandbox Code Playgroud)
我想定义一个新的宏FOO如下:
#define FOO(x,y) FOO2(x,y)
#define FOO(x,y,z) FOO3(x,y,z)
Run Code Online (Sandbox Code Playgroud)
但这不起作用,因为宏不会在参数数量上超载.
无需修改FOO2和FOO3,是有一些方法来定义一个宏FOO(使用__VA_ARGS__或以其他方式),以获得分派的相同的效果FOO(x,y)来FOO2,并FOO(x,y,z)到FOO3?
考虑以下代码:
#define F(x, ...) X = x and VA_ARGS = __VA_ARGS__
#define G(...) F(__VA_ARGS__)
F(1, 2, 3)
G(1, 2, 3)
Run Code Online (Sandbox Code Playgroud)
X = 1 and VA_ARGS = 2, 3两个宏的预期输出,这就是我用GCC得到的,但是,MSVC将其扩展为:
X = 1 and VA_ARGS = 2, 3
X = 1, 2, 3 and VA_ARGS =
Run Code Online (Sandbox Code Playgroud)
也就是说,__VA_ARGS__将其扩展为单个参数,而不是分解为多个参数.
有什么方法吗?
如何做这项工作?如何实现C99/C++ 11可变参数宏以根据给出多少参数来扩展到不同的东西?
我想知道C++和C的预处理器有多么不同.
问题的原因是关于预处理器特定问题的这个问题,其中解决问题的标准段落具有不同的措辞(和不同的段落编号),并且也是关于C++中的true和false关键字的差异.
那么,是否存在更多差异,或者这是唯一的区别.
问题的扩展是何时由C++预处理器和C预处理器以不同方式发出的源文件.
我们可以为宏参数指定默认参数值吗?
我知道没有任何类型检查,所以我希望默认值只不过是预处理器在未指定参数值的情况下用于宏扩展的一些文本.
我正在尝试实现自己的布尔类,但不能复制&&的本机语义.以下设计的代码演示了这个问题:
#include <iostream>>
class MyBool {
public:
bool theValue;
MyBool() {}
MyBool(bool aBool) {theValue = aBool;}
MyBool operator&& (MyBool aBool) {return theValue && aBool.theValue;}
};
bool f1() {std::cout << " First\n"; return false;}
bool f2() {std::cout << " Second\n"; return false;}
int main(int argc, char** argv) {
std::cout << "Native &&\n";
f1() && f2();
std::cout << "Overloaded &&\n";
MyBool(f1()) && MyBool(f2());
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译和运行时,结果是:
Native &&
First
Overloaded &&
Second
First
换句话说,&& on bools是懒惰的(正如任何C++程序员所期望的那样)但是重载的&&不是(正如这个C++程序员至少没想到的那样).
有没有办法让重载&&懒惰?我可以找到各种全面的延迟评估方案来提供类似Haskell的功能,但它们看起来像我的用例完全矫枉过正.
我试图在C中进行面向对象,并希望为符号设置一个语法糖宏
object->vtable->method(object, arg1, arg2)
Run Code Online (Sandbox Code Playgroud)
成
send(object, method, arg1, arg2)
Run Code Online (Sandbox Code Playgroud)
不幸的是,当一个方法没有参数时,会出现尾随的逗号问题
send(object, method)
Run Code Online (Sandbox Code Playgroud)
给
object->vtable->method(object, )
Run Code Online (Sandbox Code Playgroud)
是否有任何便携式(无##__VA_ARGS__或Visual Studio)方式?
我想出了一个,但我需要交换对象和方法
#define FIRST_ARG_(N, ...) N
#define FIRST_ARG(args) FIRST_ARG_(args)
#define send(msg, ...) \
FIRST_ARG(__VA_ARGS__)->vtable->msg(__VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)
许可证
send(method, object)
send(method, object, arg1, arg2)
Run Code Online (Sandbox Code Playgroud)
编辑
在下面两个很好的答案的帮助下,我将使用这些宏来完成.它最多可以处理16个参数,但可以轻松扩展
#define SEND_NO_ARG(obj, msg) obj->vtable->msg(obj)
#define SEND_ARG(obj, msg, ...) obj->vtable->msg(obj, __VA_ARGS__)
#define GET_18TH_ARG(arg1, arg2, arg3, arg4, arg5, \
arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, \
arg16, arg17, arg18, ...) arg18
#define SEND_MACRO_CHOOSER(...) \
GET_18TH_ARG(__VA_ARGS__, …Run Code Online (Sandbox Code Playgroud) 我试图让Bloomberg的BDE库在Visual Studio 2015中编译.因为它们重新实现了编译器通常提供的标准库,所以有一些头文件的名称与标准库名称完全匹配,例如stddef.h.它们可选地允许您关闭标准库的覆盖,为此,它们重新实现的文件可选地只包括原始编译器提供的版本,例如stddef.h.他们这样做包括通过宏,如下所示:
# if defined(BSLS_COMPILERFEATURES_SUPPORT_INCLUDE_NEXT)
# include_next <stddef.h>
# else
# include BSL_NATIVE_C_LIB_HEADER(stddef.h)
# endif
Run Code Online (Sandbox Code Playgroud)
在哪里BSL_NATIVE_C_LIB_HEADER扩展到这样的东西:
#if defined(BSLS_PLATFORM_CMP_SUN) // Sun Compiler
# define BSL_NATIVE_C_LIB_HEADER(filename) <../include/filename>
#elif defined(BSLS_PLATFORM_CMP_CLANG) || defined(BSLS_PLATFORM_CMP_GNU)
// Clang and GCC use 'include_next'
#elif defined(BSLS_PLATFORM_CMP_HP) // HP Compiler
# define BSL_NATIVE_C_LIB_HEADER(filename) <../include_std/filename>
#else
// Most other compilers
# define BSL_NATIVE_C_LIB_HEADER(filename) <../include/filename>
#endif
Run Code Online (Sandbox Code Playgroud)
问题是Visual Studio 2015 引入了一些重构,将一些 C标准库头文件移动到这样的路径:C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt.这显然意味着 <../include/filename>将不再找到移动的文件.问题是所有文件都没有移动.例如,iso646.h …
是否可以让预处理器宏确定其参数是否为字符串(文字)?
例如:
#define IS_STRING(token) ???
IS_STRING("foo") // expands to 1
IS_STRING(foo) // expands to 0
Run Code Online (Sandbox Code Playgroud) 为什么此线程中的一条消息的作者在宏中使用了额外的逗号?
#define PRINT_STRING_MACRO_CHOOSER(...) \
GET_4TH_ARG(__VA_ARGS__, PRINT_STRING_3_ARGS, \
PRINT_STRING_2_ARGS, PRINT_STRING_1_ARGS, )
Run Code Online (Sandbox Code Playgroud)