These are indeed several questions in one.
About this
...
In my opinion, using this
should be completely redundant, but compiler support for C ++ 11 is not completely universal. This should work in accordance with the C ++ 11 standard:
struct Base { void func() noexcept; }; struct Derived() { void func() noexcept(noexcept(Base::func())) {} };
Note that base_func()
is a non-static member function, but since it appears in the “unpublished operand”, everything is fine. Starting at n3337 sec 4.1.1:
An identifier that denotes a non-static data element or non-stationary function of a class member can only be used:
...
- if this id expression denotes a non-static data element and it appears in an unvalued operand.
However, some compilers do not support this. Then you are forced to use std::declval
:
#include <utility> struct Base { void func() noexcept; }; struct Derived() { void func() noexcept(noexcept(std::declval<Base>().func())) {} };
About availability ...
I read the relevant parts of the standard about “unvalued operands” and “access control for elements”, and I came to the conclusion that the standard is a bit ambiguous. It mentions that the name protected
can only be used by members, friends, and derived classes. The question is whether inexperienced operands use the names of the participants that appear in them. They, of course, do not use odr-use member names and can even use member names if no definition is given, and this ambiguity is precisely why the term "odr-use" exists! For instance,
int f(); // No definition anywhere in program int x = sizeof(f()); // Completely valid, even without definition of f struct X { X() = delete; // Cannot use this constructor }; int xsize = sizeof(X{}); // Completely valid
Although this is somewhat unclear, it’s hard for me to imagine that a C ++ committee could allow you to use remote member functions on unvalued operands but not inaccessible member functions. However, I am not sure.
Please note that the above code compiles without errors with both GCC and Clang. However, the following code does not contain:
class X { X(){} }; class Y { Y() = delete; }; bool xokay = noexcept(X{});
Both GCC and Clang accept Y, but not X, which seems a little strange, to say the least. The following code is accepted by the Clan, but not GCC, and using std::declval
does not help:
class Base { protected: void func(); }; class Derived : public Base {
What a mess.
conclusions
The conclusion is that there seems to be a lot of inconsistency to get around and a lot of gaps between current compilers and the C ++ 11 specs.