麻烦在宏中使用模板参数

时间:2010-11-28 07:57:16

标签: c++ templates parameters macros

我正在尝试编译下面这段代码,我在专门用于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;
}

我得到的错误如下:

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.

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

6 个答案:

答案 0 :(得分:10)

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

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

// error, NOT valid!
template<> struct AClass<(int)> { X a; };

我通过在括号中传递类型名称然后从中构建函数类型来解决这个问题(并且可能会使用相同的方法)

template<typename T> struct get_first_param;
template<typename R, typename P1> struct get_first_param<R(P1)> {
  typedef P1 type;
};

使用它,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; 
};

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

答案 1 :(得分:9)

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);
}

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

答案 2 :(得分:6)

这里有几个问题。

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

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

  1. 你不能在宏调用过程中使用逗号,它只是失败,BOOST_FOREACH是一个众所周知的库,但他们唯一能做的就是告诉用户它的参数不应该包含逗号,除非它们可以用括号括起来,但情况并非总是如此
  2. 即使发生了替换,您的代码也会在C ++ 03中失败,因为它会在模板特化的末尾创建一个>>符号,这将无法正确解析。
  3. 有预处理/模板元编程技巧,但更简单的解决方案是使用不带逗号的类型:

    typedef std::vector<int, std::allocator<int> > FooVector;
    specialize_AClass(FooVector)
    

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

    SPECIALIZE_ACLASS
    

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

答案 3 :(得分:2)

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

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

答案 4 :(得分:1)

如果您愿意在调用宏之前添加更多代码,则可以始终将其作为解决方法:

typedef std::vector<int,std::allocator<int> > myTypeDef; 
specialize_AClass(myTypeDef) //works

答案 5 :(得分:-1)

您的代码还有很多其他问题,但要解决具体问题,预处理器只会将<>视为小于和大于运算符。

这就是它对C ++的了解程度。

可以使用一些技巧来允许模板表达式作为宏参数传递,但初学者的简单和极大的最佳答案是:

不要这样做。

干杯&amp;第h。,