简单继承——奇怪的编译器错误

3

我有一段简单的代码,用来包装struct timespec并添加了它的最小值和最大值的静态成员。

#include <sys/stat.h>
#include <limits>
struct Timespec : public timespec {
    Timespec() :timespec() {};
    Timespec(decltype(tv_sec) s, 
                     decltype(tv_nsec) ns
            ) {
        tv_sec = s;
        tv_nsec = ns;
    }
    static const Timespec max;
    static const Timespec min;
};

const Timespec Timespec::min  = Timespec(0,0);
const Timespec Timespec::max  = Timespec(
        std::numeric_limits<decltype((timespec().tv_sec))>::max(), 
        std::numeric_limits<decltype((timespec().tv_nsec))>::max()
    );

代码可以成功编译,但是如果我把末尾两行的decltype((timespec()/*...*/替换为decltype((Timespec()/*...*/,就会出现以下错误:

$ make timespec.o
g++ -std=c++0x   -c -o timespec.o timespec.cc
In file included from timespec.cc:2:0:
/usr/include/c++/4.8/limits: In instantiation of ‘static constexpr _Tp std::numeric_limits<_Tp>::max() [with _Tp = long int&]’:
timespec.cc:18:55:   required from here
/usr/include/c++/4.8/limits:313:48: error: value-initialization of reference type ‘long int&’
       max() _GLIBCXX_USE_NOEXCEPT { return _Tp(); }
                                                ^
/usr/include/c++/4.8/limits:313:51: error: body of constexpr function ‘static constexpr _Tp std::numeric_limits<_Tp>::max() [with _Tp = long int&]’ not a return-statement
       max() _GLIBCXX_USE_NOEXCEPT { return _Tp(); }
                                               ^

它应该这么做吗?


请展示出现错误的实际代码。 - Kerrek SB
你可能希望使用 std::remove_reference_t - Kerrek SB
2
去掉多余的括号。 - T.C.
1个回答

5

decltype(unparenthesized class member access)返回引用的实体声明类型。

decltype((class member access))返回不同的内容。如果类成员访问表达式的类型是T,那么如果表达式是左值,返回的类型是T&,如果表达式是xvalue,则返回T&&,如果表达式是prvalue,则返回T

CWG 616之前,如果E2指定了非静态数据成员且类型不是引用类型,则E1.E2具有与E1相同的值类别。因此,对于struct A { double x; };decltype(A().x)decltype((A().x))都是doubleA()是一个prvalue)。

在CWG 616之后,如果E2指定了非引用类型的非静态数据成员,则E1.E2现在是一个左值,如果E1是一个左值,否则是一个xvalue(再次提醒)。因此,decltype(A().x)应该是double,而decltype((A().x))应该是double &&

由于CWG 616是一个缺陷报告,它具有追溯效力;原始代码在符合规范的编译器中不应该被编译。

你观察到的实际行为似乎是编译器的一个bug。即使它没有实现CWG 616的解决方案,标准的任何修订版本都不允许它区分timespec().tv_nsecTimespec().tv_nsec,或者使decltype((timespec().tv_nsec))返回左值引用。


报告:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67633。Clang在这里的行为至少是一致的,并且表明他们还没有实现CWG 616的解决方案。 - T.C.
正确,clang目前尚未实现CWG616。 - Marco A.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接