我正在使用clang++-3.4
开发一个C ++ 11项目,并决定使用g++-4.8.2
进行编译,以防产生的错误有任何差异。事实证明,g ++拒绝了一些clang ++接受的代码。我已将问题减少到下面给出的MWE。
enum { a };
template <class T>
struct foo
{
static constexpr auto value = a;
};
int main()
{
static constexpr auto r = foo<int>::value;
}
foo.cpp:5:23:错误:使用匿名类型声明的'
const<anonymous enum> foo<int>::value
',但从未定义[-fpermissive]static const auto value = A;
我想帮助回答以下两个问题:
哪种编译器对标准的解释是正确的?我假设一个编译器接受或拒绝代码是对的,另一个是错误的。
如何解决此问题?我无法为匿名枚举命名,因为它来自第三方库(在我的情况下,枚举为Eigen::RowMajor
和Eigen::ColMajor
)。
答案 0 :(得分:14)
GCC 不准确地拒绝您的代码段,根据 C ++ 11 标准(N3337),它是合法的。带有证据和解释的报价位于本文末尾。
解决方法(A) - 添加缺少的定义
template <class T>
struct foo {
static constexpr auto value = a;
typedef decltype(a) value_type;
};
template<class T>
constexpr typename foo<T>::value_type foo<T>::value;
解决方法(B) - 使用枚举的基础类型作为占位符
#include <type_traits>
template <class T>
struct foo {
static const std::underlying_type<decltype(a)>::type value = a;
};
如上所述,该代码段是合法的 C ++ 11 ,可以在以下引用部分中阅读。
我们什么时候可以使用没有链接的类型?
[basic.link]p8
有详细的措辞,用于描述类型何时&#34;没有链接&#34; ,并且它声明未命名的枚举计数为此类型。
[basic.link]p8
还明确说明了三种不能使用这种类型的上下文,但其中一种上下文不适用于我们的使用,所以我们是安全的。
除非
,否则不带链接的类型不能用作具有外部链接的变量或函数的类型
- 该实体具有C语言链接(7.5)或
- 实体在未命名的命名空间(7.3.1)或
中声明- 实体不是odr-used(3.2)或在同一翻译单元中定义
auto
吗?是的,这可以通过以下引用证明:
7.1.6.4p
auto
说明符[dcl.spec.auto]
类型说明符也可用于在中选择语句(6.4)或迭代语句(6.5)的条件中声明变量 new-expression 的 new-type-id 或 type-id 中的type-specifier-seq (5.3.4 ),在 for-range-declaration 中,以及在成员规范中出现的 brace-or-equal-initializer 声明静态数据成员类定义(9.4.2)。
答案 1 :(得分:10)
哪种编译器对标准的解释是正确的?
gcc
不正确。 §9.4.2/ 3:
可以在类中声明文字类型的静态数据成员 使用constexpr说明符定义;如果是的话,其声明应 指定一个brace-or-equal-initializer,其中包含每个initializer子句 这是一个赋值表达式是一个常量表达式。 会员 仍然应在命名空间范围中定义,如果它是使用了 (3.2)in 程序和命名空间范围定义不应包含 初始化程序。
根据§3.2的说法,这个名字并没有被使用:
名称显示为可能评估的表达式的变量是 odr-used 除非它是满足出现在常量表达式(5.19)和左值到右值的要求的对象 转换(4.1)立即应用。
确实如此:它确实满足出现在常量表达式中的要求,并且立即应用左值到右值的转换(它用作对象的初始值设定项)。所以GCC的拒绝是不正确的。
可能的解决方法是定义成员(但没有占位符类型)。这个定义对于Clang和GCC都是足够的:
template< typename T >
constexpr decltype(a) foo<T>::value;
答案 2 :(得分:5)
decltype
的解决方法:
enum { a };
template <class T>
struct foo
{
static constexpr auto value = a;
};
template <class T>
constexpr decltype(a) foo<T>::value;
int main()
{
static constexpr auto r = foo<int>::value;
}