C++ 宏和模板

5
有没有一种方法可以传递参数?
std::map<std::string, float>

作为宏的参数?
(问题在于“,”被宏用来分隔。)
std::map<std::string

并且

float> 

作为单独的参数。我希望避免这种情况。


我认为他们第一次就听到你了… - Adriaan Stander
应该是C还是C++? - AnT stands with Russia
3
好的,我会尽力为您翻译。以下是需要翻译的内容:只是好奇,我们能看到涉及的宏吗?也许有更好的方法来完成您正在使用它的任务。 - Chris Lutz
3
@AndreyT:由于他使用了map,我会说是C++...不是吗? - Matthieu M.
6个回答

7

不,除非使用typedef,否则没有办法做到这一点。例如,BOOST_FOREACH也存在同样的问题。


如果你愿意进行一些预处理编程,那么是有办法的。但这可能会给用户带来一些负担,具体取决于你想要什么,宏也需要定制以处理它...请参见我的答案。 - Matthieu M.

6
尝试使用模板而不是宏。
斯科特·迈耶斯:Effective C++第2项:优先使用const、枚举和内联,而非#define。

1
这里不适用于“项目2”:它并未提及模板,仅涉及常量……虽然我同意一般观点,但如果总是有可能的话……那就太好了。 - Matthieu M.
1
这是第二项的内联函数。我在这里提到模板,因为宏不关心类型,所以通常无法用普通函数替换它们。但使用模板可以让你有这样的能力。我认为Meyer使用了min/max宏来演示模板。 - Totonga

5

是的,有一种方法,不过这是一种间接的方法。

正如你所说,宏在解释时相当简单。不过它仍然能够识别括号。

例如:BOOST_MPL_ASSERT((boost::is_same<int,int>))

它通过使用另一个层次的括号来工作,从宏的角度形成一个Tuple

如果您使用Boost.Preprocessor库,您可以轻松地“展开”一个Tuple以获取其内容。不幸的是,您需要预先知道元组的大小,因此需要一个额外的参数。

#define MY_MACRO(Size, TemplatedType, Name)\
  BOOST_PP_TUPLE_REM(Size)(TemplatedType) Name

并且在实际操作中:

MY_MACRO(2, (std::map<int,std::string>), idToName);
    // expands to 'std::map<int,std::string> idToName'
idToName[1] = "Smith";

所以,是可以实现的,但是宏必须明确地定制以处理它。

我应该补充一下,这可能会很麻烦,因为用户需要计算“,”的数量 :/ - Matthieu M.

2
一个不太优雅的解决方法是在另一个宏中“隐藏”逗号。
#define ARGUMENT std::map<std::string, float> 
YOUR_MACRO(ARGUMENT)
#undef ARGUMENT

然而,如果YOUR_MACRO本身需要将其传播到另一个宏中的下一级,则会遇到相同的问题。


typedef可以解决嵌套宏的问题,但是它更加永久。 - Chris Lutz
我赞同使用typedef的方法。每当有一种不涉及宏且提供相同易用性的替代方案时...你最好不要使用宏。 - Matthieu M.
哦,太酷了的技巧。如果可以的话,我会给你+10分。谢谢! - BЈовић

1
是的,只要你能安排好std::map<std::string, float>作为你的最后一个或唯一的参数。只需使用__VA_ARGS__,例如:
#define MAKE_A_NEW_ONE_OF_THESE(a, ...) __VA_ARGS__ *a = new __VA_ARGS__

MAKE_A_NEW_ONE_OF_THESE(pMyMap, std::map<std::string, float>);

0
我几个月前也遇到过类似的问题,如果你在使用宏并且参数中包含逗号(','),你需要将它们用额外的括号括起来,例如:
#define DEF(ret,conv,name,args) typedef ret (conv * name)(args)

//usage
DEF(void,__cdecl,Foo,(int a1, string a2)); 

这个方法可能与某些事情冲突/在某些情况下无效,就像这个例子一样(它会导致它变成一个无效的C风格转换):

#define MY_VAR(type,name) type name

//usage
MY_VAR((std::map<std::string, float>),Map);

不过有一种解决这个问题的方法,但需要你的编译器支持可变参数宏(GCC|MSVC):

#define _W(...) __VA_ARGS__
#define VAR(x,y) x y

VAR(_W(std::map<std::string, float>),Map);

宏定义中不要使用括号括起args,因为它已经带有括号了。 - Matthieu M.
如果有人使用单一参数,当使用宏时可以省略括号,这就是为什么args带有括号,其余时间不起作用,多余的括号将被删除/忽略。 - Necrolis
1
括号似乎没有被忽略。第一个示例扩展为 (std::map<std::string, float>) Map;,但这实际上会导致编译错误(因为它将 C 风格的转换应用于未声明的标识符 Map)。 - UncleBens
似乎第一个例子是一个没有成功的案例(括号只在“DEF”宏中被忽略),感谢指出,已经用“正确”的解决方案修复了它。 - Necrolis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接