替换此宏

时间:2011-04-07 10:31:27

标签: c++ macros template-meta-programming

鉴于此宏

#define MAKE_TYPE(_a, _b, _c, _d) ((_a) | ((_b) << 8) | ((_c) << 16) | ((_d) << 24))

我想替换它,以便它需要一个数组[4] 。 所以我可以写MAKE_TYPE(“ABCD”)而不是丑陋的MAKE_TYPE('A','B','C','D')

我在编译时使用它来生成一些常量。

但是,它不喜欢我传递像这样的字符串

#define MAKE_TYPE(s) ((s[3]) | ((s[2]) << 8) | ((s[1]) << 16) | ((s[0]) << 24))

错误:数组引用不能出现在常量表达式

那不起作用。所以我想我会使用模板元编程

来解决它
template< char[4] s > class MAKE_TYPE
{
 public:
 enum{ RESULT = s[3] | (s[2] << 8) | (s[1] << 16) | (s[0] << 24) };
};

不幸的是,这也行不通。我似乎无法在模板中放置char [4]。 我得到了这些错误:

错误:在's'之前预期'&gt;' 错误:'s'未在此范围内声明 错误:数组引用不能出现在常量表达式

我该怎么做?

5 个答案:

答案 0 :(得分:2)

错误消息表示它的含义:数组不能出现在常量表达式中。

模板表达式必须是常量表达式,因此数组不能出现在模板参数中。

你可以有一个指向数组的指针,但这不是你想要的。

啊,看到限制只有四个字符,您可以使用多字符常量,例如单引号中的'ABCD'。但是,然后字符的顺序是实现定义的。

您似乎尝试的另一件事是从字符常量生成类本身的名称。如果你将裸字而不是字符文字传递给宏,这是有可能的,但是,实际上并非如此。即使它有点工作,也会非常地狱般的。

答案 1 :(得分:2)

你有没有尝试过更多的括号和/或演员?

#define MAKE_TYPE(s) (int((s)[3]) | (int((s)[2]) << 8) | (int((s)[1]) << 16) | (int((s)[0]) << 24))

这对我有用,我使用的东西非常类似于FourCC代码,我的宏被许多不同的编译器使用。

答案 2 :(得分:0)

如果您知道输入为char *

template <class RT> RT MakeType( const char * _arg )
{
  return _arg[3] | (_arg[2] << 8) | (_arg[1] << 16) | (_arg[0] << 24);
}

否则:

template <class T, class RT> RT MakeType( const T &B0, const T &B1, const T &B2, const T &B3 )
{
  return B3 | (B2 << 8) | (B1 << 16) | (B0 << 24);
}

我愿意:

inline unsigned int MakeType( const char * _arg )
{
  return _arg[3] | (_arg[2] << 8) | (_arg[1] << 16) | (_arg[0] << 24);
}

并在必要时施放。

答案 3 :(得分:0)

您可以使用多字符常量,例如int four = 'four'。行为是特定于编译器的。

答案 4 :(得分:0)

这样的事情怎么样?

template <typename T>
typename boost::enable_if_c<(T('1234')==0x31323334), T>::type
make(T v)
{
    return v;
}

const int value = make('ABCD');

这是多字符常量的编译器相关行为的安全网。您可以为不同的编译器行为添加更多实现,根据需要切换字节。这假设'1234'评估的字节顺序对于每个编译器是一致的。

模板专家可能能够改进。