voi*_*ter 26 c++ enums language-lawyer auto c++11
我正在使用C++ 11项目clang++-3.4
,并决定编译使用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;
}
Run Code Online (Sandbox Code Playgroud)
foo.cpp:5:23:错误:'
const<anonymous enum> foo<int>::value
',使用匿名类型声明,但是使用但从未定义[-fpermissive]Run Code Online (Sandbox Code Playgroud)static const auto value = A;
我想帮助回答以下两个问题:
哪个编译器在解释标准时是正确的?我假设一个编译器正确接受或拒绝代码,另一个是错误的.
我该如何解决这个问题?我无法命名匿名枚举,因为它来自第三方库(在我的情况下,枚举是Eigen::RowMajor
和Eigen::ColMajor
).
Fil*_*efp 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;
Run Code Online (Sandbox Code Playgroud)
变通方法(B) - 使用枚举的基础类型作为占位符
#include <type_traits>
template <class T>
struct foo {
static const std::underlying_type<decltype(a)>::type value = a;
};
Run Code Online (Sandbox Code Playgroud)
如上所述,该片段是合法的C++ 11,可以在以下引用部分中阅读.
我们什么时候可以使用没有连接的类型?
[basic.link]p8
有一个详细的措辞,描述何时类型是"没有链接",并且它声明一个未命名的枚举计数为这种类型.
[basic.link]p8
还明确说明了三种不能使用这种类型的上下文,但其中一种上下文不适用于我们的使用,所以我们是安全的.
除非使用没有链接的类型,否则不应将其用作具有外部链接的变量或函数的类型
- 该实体具有C语言链接(7.5),或
- 实体在未命名的命名空间(7.3.1)中声明,或
- 该实体不是使用过的(3.2)或在同一翻译单元中定义
auto
在这样的背景下使用吗?是的,这可以通过以下引用证明:
7.1.6.4p
auto
符[dcl.spec.auto]
甲
auto
类型说明符也可以声明在一个选择语句(6.4)或循环语句(6.5)的状态的变量使用时,在类型说明符-SEQ的新型-ID或类型-ID的new-expression(5.3.4),在for-range-declaration中,并在一个静态数据成员中声明一个括号或等于初始化器,它出现在类定义的成员规范中(9.4.2).
Col*_*mbo 10
哪个编译器在解释标准时是正确的?
gcc
是不正确的.§9.4.2/ 3:
可以使用constexpr说明符在类定义中声明文字类型的静态数据成员; 如果是这样,它的声明应指定一个大括号或等于初始化器,其中作为赋值表达式的每个initializer子句都是一个常量表达式.该成员仍然在命名空间范围来限定,如果它是ODR使用的程序中的(3.2)和命名空间范围定义不应含有一个初始化.
并且根据§3.2,名称不是使用的:
名称显示为潜在评估表达式的变量是 odr-used, 除非它是满足出现在常量表达式(5.19)中的要求的对象,并且立即应用左值到右值转换(4.1).
确实如此:它确实满足了出现在常量表达式中的要求,并且立即应用了左值到右值的转换(它被用作对象的初始化器).所以海湾合作委员会的拒绝是不正确的.
可能的解决方法是定义成员(但没有占位符类型).这个定义对于Clang和GCC都足够了:
template< typename T >
constexpr decltype(a) foo<T>::value;
Run Code Online (Sandbox Code Playgroud)
解决方法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;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
4419 次 |
最近记录: |