c++language-lawyerstandardsboost-intrusive

Does `member_variable.a_type::b_type::static_function()` conform to the C++ standard?


In a project extending the boost.intrusive library I recently reviewed I encountered the following code in the class treap_impl:

node_ptr this_head(this->tree_type::header_ptr());
node_ptr right(this->tree_type::node_algorithms::root_node(this_head));

The code in question compiles on MSVC 17.9, but not using clang or gcc, due to an error on the second line:

...::node_algorithms is not a base of treap_impl<...>

Removing this-> from the second line resolves the error.

My questions:

  1. Does this code, specifically the this->tree_type part, comply with the C++ standard?
  2. Which section of the C++ standard is relevant here?
  3. Is there a bit of very basic C++ knowledge that I'm overlooking here?

Here is an example that reproduces the same error on gcc and clang. This also fails to compile with MSVC on compiler explorer. Sadly I'm not sure how to reproduce the exact setting described above, i.e., what's needed to make it compile with MSVC, but not with gcc/clang.

struct static_thing {
  static int value() {
    return 5;
  }
};

struct A {
  using the_type = static_thing;
};

class B {
  using a_type = A;

  void do_stuff() {
    int a(this->a_type::the_type::value());
  }
};

The error in question:

error: ‘A::the_type’ {aka ‘static_thing’} is not a base of ‘B’

Solution

  • this->a_type::the_type::value() says "find a method or callable member called value on the base class a_type::the_type and call it". It may be called as a callable, as a method with a hidden this argument or as a static method, but in any case only members and member methods are eligible for the lookup.

    That's unlike a_type::the_type::value() alone, which in that context could also have meant the same, but also had the other overload of "find a function or callable variable called value in the namespace a_type::the_type and call it without arguments". The list of base class members still has precedence as the namespace for the lookup, but you are no longer constrained to base classes alone.

    As for what the compiler understood / wanted:

    struct static_thing {
      static int value() {
        return 5;
      }
    };
    
    struct A {
      using the_type = static_thing;
    };
    
    // There is now value() from static_thing as a member on B
    // static_thing is additionally known by the alias a_type::the_type
    class B : public static_thing {
      using a_type = A;
    
      void do_stuff() {
        int a(this->a_type::the_type::value());
      }
    };
    

    Applied to your original question, the class treap_impl should have inherited from the class node_algorithms in order to gain access to the traits defined in that class.