麻烦在宏中使用模板参数

22 c++ parameters macros templates

我正在尝试编译下面的一段代码,我在专门用于std :: vector的行上得到一个错误,似乎传入的一个参数在某种程度上被假定为两个参数.它可能与角括号有关吗?

是否有一种特殊的方式/机制,通过这些参数可以正确地传递给宏?

#include <vector>

template<typename A>
struct AClass {};

#define specialize_AClass(X)\
template<> struct AClass<X> { X a; };


specialize_AClass(int) //ok

specialize_AClass(std::vector<int,std::allocator<int> >) //error

int main()
{
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

我得到的错误如下:

1 Line 55: error: macro "specialize_AClass" passed 2 arguments, but takes just 1
2 Line 15: error: expected constructor, destructor, or type conversion before 'int'
3 compilation terminated due to -Wfatal-errors.
Run Code Online (Sandbox Code Playgroud)

链接:http://codepad.org/qIiKsw4l

Joh*_*itb 10

你有两个选择.其中一个已经提到:使用__VA_ARGS__.然而,它的缺点是它不能在严格的C++ 03中工作,但需要足够的C99/C++ 0x兼容预处理器.

另一个选项是括起类型名称.但与另一个答案声称不同,它并不像仅仅使用类型名称括起来那么容易.如下编写专业化是不正确的

// error, NOT valid!
template<> struct AClass<(int)> { X a; };
Run Code Online (Sandbox Code Playgroud)

通过在括号中传递类型名称,然后构建一个函数类型,我已经解决了这个问题(并且可能会在引擎盖下使用它)

template<typename T> struct get_first_param;
template<typename R, typename P1> struct get_first_param<R(P1)> {
  typedef P1 type;
};
Run Code Online (Sandbox Code Playgroud)

用它get_first_param<void(X)>::type表示类型X.现在您可以将宏重写为

#define specialize_AClass(X) \
template<> struct AClass<get_first_param<void X>::type> { 
  get_first_param<void X>::type a; 
};
Run Code Online (Sandbox Code Playgroud)

而你只需要传递包含在括号中的类型.

  • 或者,他可以使用BOOST_PP_COMMA()或类似的函数来传递他自己的逗号. (2认同)

小智 10

template<typename TypeX, typename TypeY>
class Test
{
public:
    void fun(TypeX x, TypeY y)
    {
        std::wcout << _T("Hello") << std::endl;
        std::wcout << x << std::endl;
        std::wcout << y << std::endl;
    }
};

#define COMMOA ,

#define KK(x) x val;

void main()
{
    KK(Test<int COMMOA int>);
    val.fun(12, 13);
}
Run Code Online (Sandbox Code Playgroud)

我有一种解决这个问题的新方法.希望它可以帮到你:)


Mat*_* M. 6

这里有几个问题.

首先,宏非常愚蠢,它们很复杂,但基本上相当于一个纯文本替换过程.

因此,您公开的代码存在2个(技术)问题:

  1. 你不能在宏调用过程中使用逗号,它只是失败,BOOST_FOREACH是一个众所周知的库,但他们唯一可以做的就是告诉用户它的参数不应该包含逗号,除非它们可以包含在括号,但并非总是如此
  2. 即使发生了替换,您的代码也会在C++ 03中失败,因为它会>>在模板特化的末尾创建一个符号,这将无法正确解析.

有预处理/模板元编程技巧,但更简单的解决方案是使用没有逗号的类型:

typedef std::vector<int, std::allocator<int> > FooVector;
specialize_AClass(FooVector)
Run Code Online (Sandbox Code Playgroud)

最后,存在一个美学问题,因为它们的普遍性,宏最好给出不可能与"常规"(类型,函数,变量)名称冲突的名称.共识通常是使用所有大写标识符,如:

SPECIALIZE_ACLASS
Run Code Online (Sandbox Code Playgroud)

请注意,这不能以下划线开头,因为标准限制使用标识符匹配_[A-Z].*[^_]*__.*标准库的编译器编写者或他们想要的任何东西(那些不是表情符号:p)


Jus*_*ers 3

由于预处理器在语义分析之前运行,因此模板参数中的逗号将被解释为宏的参数分隔符。相反,您应该能够使用可变参数宏来执行以下操作:

#define specialize_AClass(...)\
template<> struct AClass< __VA_ARGS__ > { X a; };
Run Code Online (Sandbox Code Playgroud)