10

Please consider the following code snippet:

template<class Tuple>
class vector
{
public:
    typename Tuple::size_type size() const noexcept(noexcept(m_elements.size())) {
        return m_elements.size();
    }

private:
    Tuple m_elements;
};

class tuple
{
public:
    using size_type = std::size_t;

    size_type size() const { return 0; }
    size_type size() noexcept { return 0; }
};    

int main()
{
    vector<tuple> x;
    static_assert(noexcept(x.size()), "x.size() might throw");

    return 0;
}

Is the use of the member variable m_elements inside the noexcept specifier legal? GCC 5.2 (C++17) yields the compiler error m_elements was not declared in this scope. while clang 3.6 (C++17) compiles without any error.

Both compilers yield no error if I use noexcept(std::declval<Tuple const&>().size()) instead. However, as you can see, I've created a simple example class tuple where it's crucial whether or not Tuple has qualified overloads of size.

From my point of view, it's more intuitive to write noexcept(m_elements.size()) cause it's exactly the call in the function body and it takes into account that the size method of vector is const qualified (which makes m_elements a const object in the scope of the function).

So, what's the legal usage? If both are equivalent, which should I use? Should I use noexcept qualifiers at all in this scenario? The problem is that whether or not the vector functions will throw depends in all most every case on Tuple.

Barry
  • 286,269
  • 29
  • 621
  • 977
0xbadf00d
  • 17,405
  • 15
  • 67
  • 107
  • I would like to note that there [has been a question concerning the use of member variables inside a `noexcept` specification](http://stackoverflow.com/questions/27241938/noexcept-depending-on-method-of-member) here on the board, but please note that this question is related to C++11 and a compiler error generated by (some unknown version of) clang. – 0xbadf00d Mar 08 '16 at 16:00

1 Answers1

8

Clang is correct here, this is gcc bug 52869. According to [basic.scope.class], emphasis mine:

The potential scope of a name declared in a class consists not only of the declarative region following the name’s point of declaration, but also of all function bodies, default arguments, exception-specifications, and brace-or-equal-initializers of non-static data members in that class (including such things in nested classes).

The scope of m_elements includes the noexcept-specification for size().

Barry
  • 286,269
  • 29
  • 621
  • 977
  • @JonathanWakely 52869 is supposed to have been fixed in trunk ([r266224](https://gcc.gnu.org/viewcvs/gcc?view=revision&revision=266224)) but gcc still rejects OP's snippet (`__VERSION__` == `"9.0.0 20181204 (experimental)"`) – Oktalist Dec 05 '18 at 18:59
  • @Oktalist, the bug doesn't actually say it's fixed (status is still NEW). I've added a new comment with a reduced example that still fails. – Jonathan Wakely Dec 05 '18 at 20:50