简体   繁体   中英

Simple inheritance — strange compiler error

I have this simple piece of code that wraps struct timespec and adds static members for its minimum and maximum.

#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()
    );

It compiles OK, but if I replace decltype((timespec()/*...*/ with decltype((Timespec()/*...*/ in the two lines at the end, I get:

$ 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(); }
                                               ^

Should it be doing this?

decltype(unparenthesized class member access) returns the declared type of the entity referenced.

decltype((class member access)) returns something different. If the type of the class member access expression is T , then the returned type is T& if the expression is an lvalue, T&& if the expression is an xvalue, and T if the expression is a prvalue.

Before CWG 616 , if E2 names a non-static data member of non-reference type, then E1.E2 has the same value category as E1 . So given struct A { double x; }; struct A { double x; }; , decltype(A().x) and decltype((A().x)) are both double ( A() is a prvalue).

After CWG 616, E1.E2 is now an lvalue if E1 is an lvalue, and an xvalue otherwise (again, when E2 names a non-static data member of non-reference type). So decltype(A().x) should be double and decltype((A().x)) should be double && .

Since CWG 616 is a defect report, it applies retroactively; your original code should not compile in a conforming compiler.

The actual behavior you observe appears to be a compiler bug. Even if it doesn't implement CWG 616's resolution, there is nothing in any revision of the standard that allows it to differentiate between timespec().tv_nsec and Timespec().tv_nsec , or to make decltype((timespec().tv_nsec)) return an lvalue reference.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM