https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85965

            Bug ID: 85965
           Summary: G++ gives cryptic error instead of incomplete type
           Product: gcc
           Version: 8.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: psmith at gnu dot org
  Target Milestone: ---

Compiling code with GCC 8.1 / binutils 2.30 (built locally on GNU/Linux amd64)
which previously compiled and worked OK with GCC 6.2 and 7.3.

I received a very cryptic error that had me running around reworking class
implementations for quite a while before I realized the problem: I had an
incomplete type.  I don't know if there's anything G++ could do better here,
but FYI I had this code:

class Bar
{
public:
    struct Less
    {
        bool operator()(const Bar& lhs, const Bar& rhs) const;
        bool operator()(const Bar* lhs, const Bar* rhs) const;
    };
};

class Biz;

#include <set>

class Foo
{
    std::set<const Biz*, Bar::Less> _map;
};

It's not immediately clear that the incomplete Biz class is a problem,
especially in my code which is significantly more complex and crosses multiple
header files, and G++ doesn't give a very helpful (to me) error:

$ g++ -o set.o -c set.cpp
In file included from x86_64-generic-linux-gnu/include/c++/8.1.0/set:60,
                 from set.cpp:13:
x86_64-generic-linux-gnu/include/c++/8.1.0/bits/stl_tree.h: In instantiation of
'class std::_Rb_tree<const Biz*, const Biz*, std::_Identity<const Biz*>,
Bar::Less, std::allocator<const Biz*> >':
x86_64-generic-linux-gnu/include/c++/8.1.0/bits/stl_set.h:133:17:   required
from 'class std::set<const Biz*, Bar::Less>'
set.cpp:17:37:   required from here
x86_64-generic-linux-gnu/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&>{},
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If I had included the complete type for class Biz, the compiler would have seen
that Biz is a subclass of Bar and it would have been fine; adding in the header
file fixed my problem:

class Bar
{
public:
    struct Less
    {
        bool operator()(const Bar& lhs, const Bar& rhs) const;
        bool operator()(const Bar* lhs, const Bar* rhs) const;
    };
};

class Biz : public Bar
{}

#include <set>

class Foo
{
    std::set<const Biz*, Bar::Less> _map;
};

Reply via email to