1

a.h

#ifndef _A__
#define _A__
class A {
  public:
    struct Less {
      bool operator() (const A* const &k1, const A* const &k2) const
      {
        return k1->_a < k2->_a;
      }
    };
    A(int a) : _a(a)
  {
    ;
  }
    virtual ~A()
    {
      ;
    }
  private:
    int _a;
};

#endif

b.h

#ifndef _B__
#define _B__
#include "a.h"

class B : public A {
  public:
    B(int a) : A(a)
  {
    ;
  }
    ~B()
    {
      ;
    }
};

#endif // _B__

c.cpp

#include <set>
#include "a.h"
class B;
class C
{
  std::set<B*, A::Less> _set;
};

When c.cpp is compile with g++ 8.1, it fails to compile with this static check error

/export/dev6/rajpal/gcc/8.1.0/bin/g++ -c c.cpp
In file included from /export/dev6/rajpal/gcc/8.1.0/include/c++/8.1.0/set:60,
                 from c.cpp:1:
/export/dev6/rajpal/gcc/8.1.0/include/c++/8.1.0/bits/stl_tree.h: In instantiation of 'class std::_Rb_tree<B*, B*, std::_Identity<B*>, A::Less, std::allocator<B*> >':
/export/dev6/rajpal/gcc/8.1.0/include/c++/8.1.0/bits/stl_set.h:133:17:   required from 'class std::set<B*, A::Less>'
c.cpp:6:25:   required from here
/export/dev6/rajpal/gcc/8.1.0/include/c++/8.1.0/bits/stl_tree.h:452:21: error: static assertion failed: comparison object must be invocable with two arguments of key type
       static_assert(__is_invocable<_Compare&, const _Key&, const _Key&>{},
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I understand error is because at compile time, compiler is not able to determine how to compare _Key=B* and if I make available definition of B, it should work just fine.

But, my question is if there is any way to tell compiler that B is actually derived from A and there is a way to compare A objects.

Also please note that I don't want to change std::set<B*, A::Less> to std::set<A*, A::Less> which should also fix this problem.

Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • This doesn't address the question, but names that begin with an underscore followed by a capital letter (`_A__`, `_B__`) and names that contain two consecutive underscores (`_A__`, `_B__`) are reserved for use by the implementation. Don't use them in your code. – Pete Becker Jul 17 '18 at 20:24
  • This also doesn't address the question, but passing a pointer by const reference is pointless. The signature of `A::Less::operator()` can be `bool operator()(const A* k1, const A* k2)`. – Pete Becker Jul 17 '18 at 20:27
  • Thanks Pete for your comments. It's haste than normal practice when I used _A__ – rajpal gusain Jul 18 '18 at 15:23
  • I've also bumped into this error. This is unfortunate to be forced to provide full definition just for this; and I'd say it should be reported as a bug! – hedayat Mar 19 '19 at 15:02

2 Answers2

2

Well, this is actually a libstdc++ bug, and will be fixed in GCC 8.4: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85965

hedayat
  • 184
  • 1
  • 10
1

But, my question is if there is any way to tell compiler that B is actually derived from A

The only way to do that is to make the definition of B visible where you need that information.

There is nothing like forward declaration of classes to indicate that B is derived from A.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • I know it but it means that I will have to include b.h at places where it's actually not required in earlier versions of gcc. And it doesn't make much sense to expose details of class B when what is required is if class B has compare function or not. – rajpal gusain Jul 18 '18 at 15:26