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.
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.
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>{}) { }
};
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)
Related
There are two classes:
class A {
public:
virtual void foo( int bar );
}
class B {
virtual void foo( string bar, int baz);
}
Now, the class(es) I'm building can derive from either class. But there's some common helper code, so I want to factor it out into a base class.
This common code must be called from foo and should take same arguments as the corresponding foo method. So I declare this template class, but don't know, whether it is possible to "extract" foo's signature from the template argument (which is a base class -- either A or B):
template<class Base>
class CommonBase : public Base {
public:
// how do I overload Base::foo here?
void foo(/*Base::foo arguments here*/) {
commonCode(/*Base::foo arguments here*/);
}
protected:
// how do I define commonCode with Base::foo signature below?
void commonCode(/*Base::foo arguments here*/) { ... }
}
I have little experience with C++ templates, so wondering -- is it even possible?
One solution I see is to add another template parameter for method signature and pass it explicitly when specializing. But it feels redundant as the knowledge of foo signature will be already contained in the Base class parameter (and compilation should fail if Base does not provide foo at all).
One solution I see is to add another template parameter for method signature and pass it explicitly when specializing.
This is on the right track, but you don't have to pass it explicitly; you can extract the type from the base class:
template<class Base, class... Arg>
class CommonBaseImpl : public Base {
public:
// how do I overload Base::foo here?
void foo(Arg... arg) override {
commonCode(std::forward<Arg>(arg)...);
}
protected:
// how do I define commonCode with Base::foo signature below?
void commonCode(Arg... arg) { ... }
};
template <class Base, class Foo = decltype(&Base::foo)>
struct BaseSelector;
template <class Base, class... Arg>
struct BaseSelector<Base, void (Base::*)(Arg...)>
{
using type = CommonBaseImpl<Base, Arg...>;
};
template <class Base>
using CommonBase = typename BaseSelector<Base>::type;
[Live example]
This works by using class template partial specialisation to decompose the function type. The template parameter Foo of BaseSelector will hold the type of member pointer to foo. To get this type, we use decltype(&Base::foo), the default argument for that parameter.
However, we need to access the individual argument types from within that type. This is normally done using template partial specialisation, as here. Basically, the primary template says: "This class template takes two types, Base and Foo." They're types and we know nothing more about them. We also don't use them for anything (the primary template is not even defined).
Then, we provide a specialisation. That effectively says: "When the type Foo happens to be a pointer to member function of Base which returns void and takes arguments of type Arg..., then do this: { partially specialised class definition }". In practice, it's just a way to assign names to the various components of the pointer-to-member type.
I was porting some code from MSVC(without permissive-) to linux and I learned that if you call constructor of a template base class in initializer list of your class you must specify all the template parameters or you get an error.
Seems kind of redundant, since if you make a mistake in retyping the template parameters it is a hard error:
error: type 'Base<int, true>' is not a direct or virtual base of
'Derived'
full code here:
template <typename T, bool has_x>
struct Base
{
Base(T t): t_(t){
}
T t_=0;
};
template <typename T>
class Derived : public Base<T, false>
{
public:
// : Base<T, true> is hard error
Derived(const T& t) : Base<T, false>(t) {}
};
int main()
{
Derived d(47);
}
Is there a strong reason for this, or just standardization process never took time to special case this use case?
You only need to do that when Derived is a template and the type of the base depends on its template parameters.
This compiles, for example:
template <typename T>
class Derived : public Base<int, false>
{
public:
Derived(const T& t) : Base(t) {}
};
As far as I know, here (in member initializer list) Base is actually the injected-class-name of Base<...>, inherited from it like everything else.
And if the type of the base does depend on the template parameters, its inherited injected-class-name becomes inaccessible (at least directly), just like any other member inherited from it.
For a member variable/function, you'd add this-> to access it, but for a type member you need Derived:::
template <typename T>
class Derived : public Base<T, false>
{
public:
Derived(const T& t) : Derived::Base(t) {}
};
What would be the syntax to inherit constructors (some of them are template) from a class template in C++11 ?
template <class T>
struct Base
{
using type = T;
explicit constexpr Base(const type& x): value{x} {};
template <class U> explicit constexpr Base(U&& x): value{std::forward<U>(x)} {};
type value;
}
struct Derived: Base<bool>
{
using Base::Base<bool>; // Does not seem to work ?!?
}
You derive from Base<bool>. So your base class is Base<bool>, and inheriting the constructors is done via
using Base<bool>::Base;
Live on Coliru
You do not need Base<bool> after the ::, in fact the code doesn't compile if you put it. The constructors are still referred to as Base, and not Base<bool>. This is consistent with referring to member functions of class templates: you use e.g. void Foo<int>::f() and not void Foo<int>::f<int>() to refer to the Foo's member function f().
Template methods allows to span a set of method instances for different static type of arguments. Automatic argument deduction avoids duplication of information.
We are faced with a situation in which the static type we would like to automatically deduce as a template argument is the type of the class instance itself. (On the call site, the type of the instance can be a more specialised type than the class in which the template method is declared.)
eg.
class Base
{
public:
template <class T_callingObject>
T_callingObject foo()
{
bar += 1;
// We have a strong guarantee on this cast only if T_callingObject
// is automatically deduced !
return static_cast<T_callingObject&>(*this);
}
private:
int bar;
};
class Derived : public Base
{
};
int main()
{
Base base;
Derived derived;
base = base.foo<Base>(); // we already know the type of base is Base
derived = derived.foo<Derived>(); // idem
}
The question is : Is there a way not to repeat the type of base and derived ?
Edit: CRTP on Base is not an option here, we need to have a common ancestor type.
This is generally addressed with CRTP (Curiously Recursive Template Pattern) by making Base a template itself:
template <typename D>
struct Base {
D& foo() { return static_cast<D&>(*this); }
};
and thus struct Derived: Base<Derived>.
The set of operations you can conduct on the D parameters is restricted (it is an incomplete time at the time Base<Derived> is instantiated), but in your simple case this works.
You are still left to wonder if someone will not inadvertently write struct Bar: Base<Foo> though, so this only reduces the problematic surface.
EDIT: if CRTP for Base is not allowed (which often happen), you can layer the abstractions:
struct Base { virtual ~Base() {} };
template <typename D>
struct BaseT: Base {
D& foo() { return static_cast<D&>(*this); }
};
struct Derived: BaseT<Derived> {};
Since in general if foo needs to know what D is, you no longer have a single unified type.
Let's say we have a class, MyParent:
class MyParent
{
public:
template<namespace T>
MyParent()
{
T* Something;
}
};
And a derived class, which uses this constructor:
class MyDerived : public MyParent
{
public:
MyDerived()
: MyParent<int>()
{
}
};
Then I get a compiling error, because there's ambiguity. The compiler thinks that the int is a template argument to the class, not the constructor.
How do I specify that I want the int to be an argument to the constructor?
It is not possible. From the standard section 14.8.1 Explicit template argument, it notes:
[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. ]
As noted in the comments, you would need to have the constructor take a parameter of type T (or const T &), and then have MyDerived call MyParent::MyParent with a paremeter of type int.
Note that your question is not particular to inheritance. Given your code example, you cannot instantiate MyParent at all, either because it doesn't accept a template argument list or because it has no default constructor.
In order to instantiate MyParent with a constructor template, you need to provide some way for the compiler to know the template argument, and you can't do that with a no-argument constructor. You need to give MyParent's constructor a parameter. Here's an example based on code from Alf P. Steinbach:
template <typename T>
struct UseMethodsOf {};
class MyParent
{
public:
template <typename T>
MyParent(UseMethodsOf<T>)
{
T* Something;
}
};
class MyDerived: public MyParent
{
public:
MyDerived()
: MyParent(UseMethodsOf<int>())
{
}
};