Что приводит к тому, что C4250 (класс наследует участника через доминирование) при использовании форсированной сериализации с виртуальным базовым классом?

59
7

Значение предупреждения компилятора VС++ C4250 'class1' : inherits 'class2::member' via dominance мне понятно. (Но см. здесь для объяснения.)


У меня есть проблема, когда я получаю это предупреждение при сериализации иерархии классов , которая имеет абстрактный базовый класс с boost:: serialization (1.44.0).


Обратите внимание, что мои классы не не образуют какую-либо алмазоподобную иерархию наследования, которая может вызвать это предупреждение, но предупреждение вызвано созданием экземпляра boost::detail::is_virtual_base_of_impl<...> при сериализации экземпляров производных классов, (Который, кажется, использует is_virtual_base_of из Boost.TypeTraits.)


Вот минимальный пример кода для воспроизведения предупреждения в Visual Studio 2005. Обратите внимание, что код должен быть отброшен как один в один файл cpp, и он должен компилироваться.


Обратите внимание также на две точки в коде, которые отмечены комментариями, которые вызывают предупреждение. Если BOOST_CLASS_EXPORT не используется, предупреждение не является триггером, но более интересно предупреждение также не запускается, если производный класс не использует наследование virtual! (Так что, возможно, я вообще не понимаю C4250.)


// -- std includes --
#include <iostream>
#include <sstream>
#include <string>

// -- boost serialization --
#define BOOST_SERIALIZATION_DYN_LINK
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/export.hpp>

// Base with serialization support
struct Base
{
virtual ~Base() {};
virtual void DoStuff() const {
std::cout << "Base@[" << static_cast<const void*>(this) << "]::DoStuff() called\n";
}

template<class Archive> // serialization support!
void serialize(Archive & ar, const unsigned int file_version) { /*empty*/ }
};

// (The only) Specific class with ser. support
struct Concrete2 : virtual/*!C4250!*/ public Base
{
virtual void DoStuff() const {
std::cout << "Concrete2@[" << static_cast<const void*>(this) << "]::DoStuff() called\n";
}

template<class Archive> // serialization support!
void serialize(Archive & ar, const unsigned int ver) {
ar & boost::serialization::base_object<Base>(*this);
// This is just a test - no members neccessary
std::cout << "Concrete2::serialize!" << typeid(ar).name() << "\n";
}
};
// Without guid export -> *no* C4250, even *with* virtual inheritance
// (however, can't be serialized via base class pointer anymore)
BOOST_CLASS_EXPORT(Concrete2);

BOOST_CLASS_TRACKING(Concrete2, boost::serialization::track_never);

int main() {
using namespace std;
Concrete2 obj1;
obj1.DoStuff();

// The following test code is not neccessary to generate the warning ...
// (but is neccessary to show if base-pointer serialization works at runtime)
Base* ref1 = &obj1;
ostringstream out_buf;
boost::archive::text_oarchive out_archive(out_buf);
out_archive << ref1;
const string buf = out_buf.str();

cout << "Serialized obj:\n~~~~\n";
cout << buf;
cout << "\n~~~~~\n";

std::istringstream in_buf(buf);
boost::archive::text_iarchive in_archive(in_buf);
// Concrete2 obj2;
Base* ref2;
in_archive >> ref2;
if(ref2)
ref2->DoStuff();
delete ref2;
}


И вот предупреждение компилятора (ugh!):


1>...\boost_library-1_44_0\boost\type_traits\is_virtual_base_of.hpp(61) : warning C4250: 'boost::detail::is_virtual_base_of_impl<Base,Derived,tag>::X' : inherits 'Concrete2::Concrete2::DoStuff' via dominance
1> with
1> [
1> Base=type,
1> Derived=Concrete2,
1> tag=boost::mpl::bool_<true>
1> ]
1> ...\boostserializewarningtest\vbc.cpp(27) : see declaration of 'Concrete2::DoStuff'
...
1> ...\boost_library-1_44_0\boost\mpl\eval_if.hpp(40) : see reference to class template instantiation 'boost::mpl::if_<T1,T2,T3>' being compiled
1> with
1> [
1> T1=boost::is_virtual_base_of<type,Concrete2>,
1> T2=boost::mpl::identity<boost::serialization::void_cast_detail::void_caster_virtual_base<Concrete2,type>>,
1> T3=boost::mpl::identity<boost::serialization::void_cast_detail::void_caster_primitive<Concrete2,type>>
1> ]
1> ...\boost_library-1_44_0\boost\serialization\void_cast.hpp(279) : see reference to class template instantiation 'boost::mpl::eval_if<C,F1,F2>' being compiled
1> with
1> [
1> C=boost::is_virtual_base_of<type,Concrete2>,
1> F1=boost::mpl::identity<boost::serialization::void_cast_detail::void_caster_virtual_base<Concrete2,type>>,
1> F2=boost::mpl::identity<boost::serialization::void_cast_detail::void_caster_primitive<Concrete2,type>>
1> ]
1> ...\boost_library-1_44_0\boost\serialization\base_object.hpp(68) : see reference to function template instantiation 'const boost::serialization::void_cast_detail::void_caster &boost::serialization::void_cast_register<Derived,Base>(const Derived *,const Base *)' being compiled
1> with
1> [
1> Derived=Concrete2,
1> Base=type
1> ]
...
1> ...\boost_library-1_44_0\boost\serialization\export.hpp(128) : while compiling class template member function 'void boost::archive::detail::`anonymous-namespace'::guid_initializer<T>::export_guid(boost::mpl::false_) const'
1> with
1> [
1> T=Concrete2
1> ]
1> ...\boostserializewarningtest\vbc.cpp(40) : see reference to class template instantiation 'boost::archive::detail::`anonymous-namespace'::guid_initializer<T>' being compiled
1> with
1> [
1> T=Concrete2
1> ]

спросил(а) 2010-11-03T23:03:00+03:00 10 лет, 1 месяц назад
1
Решение
108

Причиной является проверка is_virtual_base_of с помощью свойств типа boost. Эта контрольная конструкция будет генерировать предупреждение C4250, если проверка прошла успешно, как видно из этого примера:


...
struct base {
virtual void mf() { };
};
struct derived_normal : public base {
virtual void mf() { };
};
struct derived_virt : virtual public base {
virtual void mf() { };
};

int main() {
using namespace std;

cout << "boost::is_virtual_base_of<base, derived_normal>::value reports: ";
// The following line DOES NOT cause C4250
cout << boost::is_virtual_base_of<base, derived_normal>::value << endl;

cout << "boost::is_virtual_base_of<base, derived_virt> reports: ";
// The following line causes C4250:
cout << boost::is_virtual_base_of<base, derived_virt>::value << endl;
...


FWIW, использование этого инструмента для определения типов в синтаксической последовательности происходит следующим образом:

    макрос BOOST_EXPORT_CLASS
      макрос BOOST_CLASS_EXPORT_IMPLEMENT
        struct guid_initializer (in export.hpp) →
        (...) void_cast.hpp/ void_cast_register → is_virtual_base_of используется здесь


Насколько я могу судить, предупреждение в этом случае совершенно безвредно и может быть предотвращено путем упаковки заголовка в:


#pragma warning( push )
#pragma warning( disable : 4250 ) // C4250 - 'class1' : inherits 'class2::member' via dominance
#include ...
#pragma warning( pop ) // C4250

ответил(а) 2010-11-05T10:44:00+03:00 10 лет назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема