我有以下代码(不,模板没有在任何地方实例化):
#define cAssert( expr ) typedef char __C_ASSERT__[( expr )?1:-1]
template<int t>
void f()
{
cAssert( t != 0 );
cAssert( t != 2 );
}
它与Visual C++一起编译得很好(当然,当t
既不是0也不是2时)。然而,gcc(4.9.0 及更早版本 - 您可以在 http://gcc.godbolt.org/上测试它们)输出以下内容:
In function ‘void f()’:
1 : error: conflicting declaration ‘typedef char __C_ASSERT__ [((t != 2) ? 1 : (-1))]’
#define cAssert( expr ) typedef char __C_ASSERT__[( expr )?1:-1]
如果我只留下一个cAssert()
(两个中的任何一个) - 它可以很好地编译。只有当我同时拥有它们时,问题才存在。
为什么 gcc 会拒绝此代码,我该如何解决此问题?
为什么这不起作用。
一个半修复:
#define cAssertbraces( expr ) typedef char __C_ASSERT_BRACES__[( expr )?1:-1]
template<class T>
void cAssert(T v1, T v2) { {cAssertbraces( v1 != v2 );} }
template<int t>
void f()
{
{cAssertbraces( t != 0 );}
{cAssertbraces( t != 2 );}
cAssert(t, 0);
cAssert(t, 2);
}
或者,使用如下__LINE__
:
#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(!!(COND))*2-1]
#define COMPILE_TIME_ASSERT3(X,L) STATIC_ASSERT(X,static_assertion_at_line_##L)
#define COMPILE_TIME_ASSERT2(X,L) COMPILE_TIME_ASSERT3(X,L)
#define COMPILE_TIME_ASSERT(X) COMPILE_TIME_ASSERT2(X,__LINE__)
...
COMPILE_TIME_ASSERT( t != 2 );
我从这个问题中得到了(那里的答案很好,应该检查)。
GCC 拒绝代码的原因本质上是,在宏展开后,您有一个不同的标记序列,其中包含该类型的声明。考虑一个更简单的例子:
template <unsigned t>
void f()
{
using type = int[t + 0];
using type = int[t ]; // Adding a +0 here makes GCC compile it fine
}
海湾合作委员会抱怨。然而,核心问题 422 涵盖了这一点,CWG 在该问题上得出结论:
我们认为,所有这些情况都应该被允许,并且只有在生成模板的实例时才需要错误。目前的标准措词似乎并不禁止这种情况,因此不需要改变。
也就是说,海湾合作委员会是错误的。