Opened 7 years ago

Closed 4 years ago

#11323 closed Bugs (fixed)

is_virtual_base_of fails to build when virtual bases and their ancestors define identical virtual functions

Reported by: leandro.gracia.gil@… Owned by: John Maddock
Milestone: To Be Determined Component: type_traits
Version: Boost 1.57.0 Severity: Problem
Keywords: Cc:

Description

The following code snippet fails to build in clang 6.0:

#include <iostream>
#include <boost/type_traits.hpp>

struct A { virtual void foo() {} };
struct B : public virtual A { virtual void foo() {} };
struct C : public B {};

int main() {
  std::cout << boost::is_virtual_base_of<B, C>::value << std::endl;
  return 0;
}

This is the compiler error it throws:

/usr/local/include/boost/type_traits/is_virtual_base_of.hpp:55:12: error: virtual function 'A::foo' has more than one final overrider in
      'boost_type_traits_internal_struct_X'
    struct boost_type_traits_internal_struct_X : public Derived, virtual Base 
(...)

The problem can be temporarily worked around by redefining virtual void foo() {} into boost_type_traits_internal_struct_X, but that does not scale as we would need to know and override every single virtual method that appears both in A and B.

Change History (4)

comment:1 by John Maddock, 7 years ago

That's nasty, as I assume this could be a common occurrence, but off the top of my head I don't see a way to fix this :(

Will have to think on this.

comment:2 by leandro.gracia.gil@…, 7 years ago

I don't see any either... I'll keep thinking too.

BTW, in case somebody seeing this is wondering why we don't simply make foo a pure virtual in A and avoid the issue altogether, let me share a more meaningful example where this becomes a problem.

#include <iostream>
#include <boost/type_traits.hpp>

// Let's say enabling RTTI is not an option in our platform / project.
#define ASSIGN_CLASS_ID() virtual int GetClassId() { return __COUNTER__; }       

struct A { ASSIGN_CLASS_ID(); };
struct B : public virtual A { ASSIGN_CLASS_ID(); };
struct C : public B { ASSIGN_CLASS_ID(); };

int main() {
  std::cout << boost::is_virtual_base_of<B, C>::value << std::endl;
  return 0;
}

comment:3 by douwegelling@…, 6 years ago

Using apple LLVM 8.0.0, this fails with pure virtual base class as well:

#include <iostream>
#include <boost/type_traits.hpp>

struct A { virtual void foo() = 0; };
struct B : public virtual A { void foo() override {} };
struct C : public B {};

int main() {
  std::cout << boost::is_virtual_base_of<B, C>::value << std::endl;
  return 0;
}

fails to compile on my machine. This makes boost::serialize completely unusable in combination with virtual inheritance

comment:4 by John Maddock, 4 years ago

Resolution: fixed
Status: newclosed

Well it's only taken 3 years, but thanks to the "detection idiom" this should now be fixed in develop for all current (post C++11) compilers.

Note: See TracTickets for help on using tickets.