问题
Just curious, is it ever possible to inherit from a template class and in constructor of the derived class, call constructor of the base class which is also templated and has no arguments to deduce its types from?
template<typename T>
struct Base {
template<typename D>
Base() { // no argument of type D to infer from
static_assert(std::is_same<T,D>::value, "");
}
};
struct Derived : Base<int> {
Derived() : Base<int>::Base<int>() {} // is there a way to write it correctly?
};
I can replace template constructor by a template method in my particular case, but still it is an interesting question about the language flexibility.
回答1:
What the C++ standard says about this (section 14.8.1):
[ Note: Because the explicit template argument list follows the function template name, and because conversion member function templates and constructor member function templates are called without using a function name, there is no way to provide an explicit template argument list for these function templates. — end note ]
It's a note, not a rule, because it actually is a consequence of two other rules, one in the same section:
Template arguments can be specified when referring to a function template specialization by qualifying the function template name with the list of template-arguments in the same way as template-arguments are specified in uses of a class template specialization.
and from 12.1
Constructors do not have names.
回答2:
The template arguments of constructor templates must be deduced from their arguments, it's not possible to explicitly specify template arguments for constructors.
As such, have Base take a dummy parameter that deduces the argument:
template <typename T>
struct dummy { }; // to prevent instantiation of T
template <typename T>
struct Base
{
template <typename D>
Base(dummy<D>)
{
static_assert(std::is_same<T, D>::value, "");
}
};
struct Derived : Base<int>
{
Derived() : Base<int>(dummy<int>{}) { }
};
回答3:
By the way the question is formulated it looks going towards a nonsensical paranoia.
Just think for plain classes:
class Base
{
public:
Base() {}
};
class Derived: public Base
{
public:
Derived() //< default ctor
:Base //< this is the Base type
() //< this selects what ctor to call
{}
};
Note that you call :Base(), that resolve into Base::Base(), not :Base::Base()
Now, by templetizing Base::Base() you are in fact trying to admit that there can be many different default ctor (with ()) for Base. That's a nonsense respect ot the concept itself of "default".
Even if Base is not by itself a template, this is not possible:
class Base
{
public:
template<class T>
Base() {} //< are there infinite way to default construct Base ?!?
};
Base b; //< so how is b constructed ?
Thing gets only apparently different with varadics:
template<class T>
class Base
{
public:
template<class... S>
Base(S&&... s) { /* something to do */ }
};
class Derived: public Base<int>
{
public:
template<class... S>
Derived(S&&... s) //< Derived varadicly initialized
:Base //< base type ...
(std::forward<S>(s)...) //< ... to initialize with what
{}
};
Note that in case s is empty you are in fact calling Base::Base() from Derived()::Derived(), templetized with <> (no args)
来源:https://stackoverflow.com/questions/26553803/derive-from-template-constructor-of-template-base-class