I am trying to understand why this minimal example compiles:
https://godbolt.org/z/xYeo53GPv
template <typename T>
struct Base {
friend class boost::serialization::access;
template <class ARCHIVE>
void serialize(ARCHIVE& ar, const unsigned int /*version*/) {}
};
struct Derived : public Base<int> {
friend class boost::serialization::access;
template <class ARCHIVE>
void serialize(ARCHIVE& ar, const unsigned int /*version*/) {
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base);
}
};
Since Base
is a templated type, how is it possible to pass it into BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base)
without specifying the template parameters?
For reference, in Boost 1.77 that macro expands into
#define BOOST_SERIALIZATION_BASE_OBJECT_NVP(name) \
boost::serialization::make_nvp( \
BOOST_PP_STRINGIZE(name), \
boost::serialization::base_object<name >(*this) \
)
and boost::serialization::base_object
is defined:
template<class Base, class Derived>
typename detail::base_cast<Base, Derived>::type &
base_object(Derived &d)
{
BOOST_STATIC_ASSERT(( is_base_and_derived<Base,Derived>::value));
BOOST_STATIC_ASSERT(! is_pointer<Derived>::value);
typedef typename detail::base_cast<Base, Derived>::type type;
detail::base_register<type, Derived>::invoke();
return access::cast_reference<type, Derived>(d);
}
where Base
is Base
is (I think) getting explicitly substituted as Base
and Derived
is getting deduced as Derived
.
To reiterate, how does this compile even though we are specifying the template parameters of Base
?
CodePudding user response:
Indeed, it's not "unspecialized" but "unparameterized" which is actually okay because of a language feature. This mechanism is known as class name injection and is specified by the standard.
Like @康桓瑋 mentioned, the Base
can be used without the template arguments within the class declaration.
For some background, see e.g.