Inheriting member function that returns *this - c++

Why the *this of the derived<T> class is still of base<T> type?
I thought the typename X would take care of that.
If this looks ugly, what is a better way?
Failed Attempt:
template <typename T>
class Derived;
template <typename T, typename X>
class Base{
public:
T val;
X f(void){
return *this;
}
};
template <typename T>
class Derived: public Base<T, Derived<T> >{
};
int main(void){
Derived<int> B;
Derived<int> C = B.f();
}
Error:
test4.cpp(9): error: no suitable user-defined conversion from "Base<int, Derived<int>>" to "Derived<int>" exists
return *this;
^
detected during instantiation of "X Base<T, X>::f() [with T=int, X=Derived<int>]" at line 20
compilation aborted for test4.cpp (code 2)

You may do the downcast with:
X f(){ return static_cast<X&>(*this);}

When the compiler looks at class Base<int, Derived<int>> it has no reason to believe that there is actually a Derived<int> that inherited from it. One could do class Other : public Base<T, Derived<T>>{} and the conversion from class Base<int, Derived<int>> to Derived<int> would be incorrect, so an automatic conversion is not allowed.
If you make a rule that says that the second template parameter must be the derived type that inherits that base (which class Other violates) you can bypass the type system with a cast, but make sure the rule is not violated.

You have
X f(void){
return *this;
}
In this function, type of *this is still the base class type. There is no automatic conversion from the base type to X.
I am unable to suggest a clean solution since X can be anything at that point, not necessarily Derived<T>.
I can use:
template <typename T>
class Derived2 : public Base<T, double>
{
};
How's the base class supposed to deal with that?
The approach used in f() seems to be a design flaw.
Update
If Derived is guaranteed to have the form
template <typename T>
class Derived : public Base<T, Derived<T>>
{
};
Then, you can use:
X& f(void){
return static_cast<X&>(*this);
}
Please note that I changed the return type from X to X&. It avoids the cost of making a copy every time you call the function.

First of all, I would modify Base so that it accepts only one template parameter.
This way, it matches exactly the common form shown for the CRTP idiom.
Actually, it seems to me that there is no reason to use both T and Derived<T> as a template parameter in this case, for the latter already contains the former and T, Derived<T> is the pattern to which you want to adhere:
template<typename>
class Base;
template <typename T, template<typename> typename X>
class Base<X<T>> {
// ...
};
template <typename T>
class Derived: public Base<Derived<T>>{
// ....
};
Then you can use a promotion from the bottom as mentioned by #Jarod42:
X<T> f(void) {
return *static_cast<X<T>*>(this);
}
Note that here you are making systematically a copy of the object and probably it is not what you want.
Another option is to modify a bit the architecture and use a covariant return type (it follows a minimal, working example):
template <typename T>
class Base {
T val;
public:
virtual const Base<T>& f(void) const {
return *this;
}
};
template <typename T>
class Derived: public Base<T> {
public:
virtual const Derived<T>& f(void) const {
return *this;
}
};
int main(void) {
Derived<int> B;
Derived<int> C = B.f();
}
Which one is better for you mostly depends on the actual problem.

Related

Implementing a "virtual" method returning *this (covariant return type)

I'm writing a hierarchy of classes of C++, let's say A, B inheriting A, C inheriting A, and D inheriting B.
Now, all of these classes must have a method bar() &, whose body is:
{
A::foo();
return *this;
}
It's the exact same code, doing the exact same thing - except for the type of the return value - which returns an lvalue reference to the class' type.
Now, the signature of this method would be different for every class. But - it's essentially the same method. The thing is, the way things stand, I need to replicate the code for it many times. How can I avoid this code duplication?
I was thinking of writing some mixin with CRTP, but when I get into the details it becomes super-ugly.
Note: For the purposes of this example, bar() is only defined for lvalues so as not to get into the question of legitimacy of returning *this from an rvalue.
As Raymond Chen commented, c++23 would have deducing this which allows code like:
struct A
{
template <typename Self>
Self& bar(this Self& self) // Here self is the static type which calls bar
// so potentially the derived type
{
self.A::foo(); // or self.foo();
return self;
}
// ...
};
struct B : A{};
struct C : A{};
struct D : B{};
But currently, CRTP might help, something like:
struct A
{
// ...
};
template <typename Derived, typename Base>
struct A_CRTP : Base
{
Derived& bar()
{
A::foo();
return static_cast<Derived&>(*this);
}
// ...
};
struct B : A_CRTP<B, A> {};
struct C : A_CRTP<C, A> {};
struct D : A_CRTP<D, B> {};

CRTP pattern with variable Base

Assume that one has two base classes Base1 and Base2 for which CRTP pattern is desired.
template <typename TDerived>
class Base1 {
};
template <typename TDerived>
class Base2 {
};
Now I would like to define a Derived class such that it can be "parametrized" with a base one.
What would be the proper way to define it in C++ (C++17 if that matters)?
Below is a pseudo-C++ code
template <template <typename> class TBase>
class Derived : public TBase<Derived<TBase>> {}; // Recursion problem here
In reality such a derived class is an extension that is applicable to any base class.
From your comment:
The problem I think still exists.
Consider your own pseudo-code when fed to a compiler (and some addition):
template <typename TDerived>
struct Base1 {
auto get() const -> int {
return static_cast<TDerived const*>(this)->a;
}
};
template <typename TDerived>
struct Base2 {
auto get() const -> int {
return static_cast<TDerived const*>(this)->b;
}
};
template <template<typename> typename TBase>
struct Derived : TBase<Derived<TBase>> {
int a;
int b;
};
auto main() -> int {
auto b = Derived<Base1>{};
b.a = 1;
b.b = 2;
return b.get();
}
Live example
As you can see, that pattern is no problem for the compiler.
Now I would like to define a Derived class such that it can be "parametrized" with a base one. What would be the proper way to define it in C++ (C++17 if that matters)?
The way you posted it in the question is the right way, and works all the way to C++98.
You seem to state that there's a recursion problem here, but there is not.
You have a template class Derived with a template template parameter Base1. The compiler now "knows" that this type Derived<Base1>. It is incomplete though, until the } is reached.
Then the compiler sees the base, which is TBase<something>, which is Base1 with some template parameter. Base1 need to be instantiated. The something is Derived<Base1>, which is an incomplete type.
The compiler then instantiate Base1 with Derived<Base1>. During that process, you cannot use Derived<Base1> in a way that it would require it to be complete.
Now that the base is instantiated and a complete type, the compiler finishes to instantiate Derived<Base1>, now complete.
There is no recursion here.

Forwarding of return types of CRTP-derived class methods

I want to use "static polymorphism" via CRTP to do something like the following:
template <typename T>
struct Base
{
double get_value() const { return ((T*)this)->_get_value(); }
protected:
~Base() {}
};
struct Derived1 : public Base<Derived1>
{
double value;
Derived1() : value(3.) {}
const double& _get_value() const { return value; }
};
struct Derived2 : public Base<Derived2>
{
double _get_value() const { return 5.; }
};
This works, but I'd also like that for the case of the object being instantiated as Derived1, get_value returns a const reference to the value instead of returning a copy. So in a way, a kind of "perfect forwarding" for return values.
I tried to declare get_value's return type like this:
template <typename T>
struct Base
{
decltype(std::declval<T>()._get_value()) get_value() const { return ((T*)this)->_get_value(); }
...
but unsurprisingly GCC complained that this is an invalid use of incomplete type 'struct Derived1'.
Is there any way to go around this?
Thank you in advance! :)
The reason why GCC is rejecting the proposed solution in the OP is that Base<Derived1> is being instantiated before Derived1. This instantiation consists of an instantiation of the signatures of all member functions, but it doesn't instantiate the function bodies themselves.
So we need to defer determination of the signature/return type of the member function until after Derived1 is visible.
One way to do this is by deferring determination of the return type via decltype(auto). This makes the return type dependent on the function body (which is not immediately instantiated). It's a C++14 feature, unfortunately.
template <typename T>
struct Base
{
decltype(auto) get_value() const { return ((T*)this)->_get_value(); }
protected:
~Base() {}
};
See https://godbolt.org/z/r1T56n
This is probably covered by dcl.spec.auto and temp.inst.
Alternatively, even in C++11, you can postpone determination of the return type by turning the function into a function template, dependent on some dummy parameter if necessary:
template <typename T>
struct Base
{
template<typename U=T>
decltype(std::declval<U>()._get_value()) get_value() const {
return ((T*)this)->_get_value();
}
protected:
~Base() {}
};

Enable if/else class member template instantiation

Can anyone tell my how to enable if/else class member template based on different derived classes from pre-defined base set? Let me use the following example:
enum class Type {
TYPEA,
TYPEB
};
// Predefined in libraries.
class BaseA {...};
class BaseB {...};
class Foo {
template <typename Derived, Type type>
void foo();
};
// User-derived
class DerivedA : public BaseA {};
class DerivedB : public BaseB {};
Normally we need two template typenames for calling the member foo.
Foo obj;
obj.foo<DerivedA, Type::TypeA>()
obj.foo<DerivedB, Type::TypeB>();
However, this native approach seems lengthy because the second template argument Type::TypeA and Type::TypeB can obviously be deduced by compiler through the first argument DerivedA and DerivedB, if they are derived from pre-defined base properly. I notice that c++11 provides is_base_of template but I am not sure how to use it in my case. To be more specific, below is the expected solution:
obj.foo<DerivedA>(); // Automatically deduce type = Type::TypeA
obj.foo<DerivedB>(); // Automatically deduce type = Type::TypeB
And if the compile fails to deduce the Type from the first typename, it should it just goes back to the normal declaration obj.foo<MyClass, MyType> where MyType is either Type::TypeA or Type::TypeB.
Sounds like you just want a default template argument:
class Foo {
template <typename Derived, Type type = get_type_from<Derived>::value>
void foo();
};
Where get_type_from<> is a metafunction to be filled in later based on how you actually figure out the Types.
template<Type t>
using etype_tag = std::integral_constant<Type, t>;
template<class T>
struct tag_t {
using type=T;
template<class D,
std::enable_if_t<std::is_base_of<T, D>::value, int>* =nullptr
>
constexpr tag_t( tag_t<D> ) {}
constexpr tag_t() = default;
constexpr tag_t(tag_t const&) = default;
};
template<class T>
constexpr tag_t<T> tag{};
constexpr etype_tag<Type::TYPEA> get_etype( tag_t<BaseA> ) { return {}; }
constexpr etype_tag<Type::TYPEB> get_etype( tag_t<BaseB> ) { return {}; }
template<class T>
constexpr decltype( get_etype( tag<T> ) ) etype{};
Now etype<Bob> is a compile-time constant integral constant you want.
class Foo {
template <typename Derived, Type type=etype<Derived>>
void foo();
};
makes the 2nd argument (usually) redundant.
You can extend get_etype with more overloads in either the namespace where etype is declared, or in the namespace of tag_t, or in the namespace of the type you are extending get_etype to work with, and etype will automatically gain support (assuming it is used in a context where the extension is visible: failure of that requirement leaves your program ill formed).
Live example

CRTP with Protected Derived Member

In the CRTP pattern, we run into problems if we want to keep the implementation function in the derived class as protected. We must either declare the base class as a friend of the derived class or use something like this (I have not tried the method on the linked article). Is there some other (simple) way that allows keeping the implementation function in the derived class as protected?
Edit: Here is a simple code example:
template<class D>
class C {
public:
void base_foo()
{
static_cast<D*>(this)->foo();
}
};
class D: public C<D> {
protected: //ERROR!
void foo() {
}
};
int main() {
D d;
d.base_foo();
return 0;
}
The above code gives error: ‘void D::foo()’ is protected with g++ 4.5.1 but compiles if protected is replaced by public.
It's not a problem at all and is solved with one line in derived class:
friend class Base< Derived >;
#include <iostream>
template< typename PDerived >
class TBase
{
public:
void Foo( void )
{
static_cast< PDerived* > ( this )->Bar();
}
};
class TDerived : public TBase< TDerived >
{
friend class TBase< TDerived > ;
protected:
void Bar( void )
{
std::cout << "in Bar" << std::endl;
}
};
int main( void )
{
TDerived lD;
lD.Foo();
return ( 0 );
}
As lapk recommended, problem can be solved with simple friend class declaration:
class D: public C<D> {
friend class C<D>; // friend class declaration
protected:
void foo() {
}
};
However, that exposes all protected/private members of derived class and requires custom code for each derived class declaration.
The following solution is based on the linked article:
template<class D>
class C {
public:
void base_foo() { Accessor::base_foo(derived()); }
int base_bar() { return Accessor::base_bar(derived()); }
private:
D& derived() { return *(D*)this; }
// accessor functions for protected functions in derived class
struct Accessor : D
{
static void base_foo(D& derived) {
void (D::*fn)() = &Accessor::foo;
(derived.*fn)();
}
static int base_bar(D& derived) {
int (D::*fn)() = &Accessor::bar;
return (derived.*fn)();
}
};
};
class D : public C<D> {
protected: // Success!
void foo() {}
int bar() { return 42; }
};
int main(int argc, char *argv[])
{
D d;
d.base_foo();
int n = d.base_bar();
return 0;
}
PS: If you don't trust your compiler to optimize away the references, you can replace the derived() function with the following #define (resulted in 20% fewer lines of disassembly code using MSVC 2013):
int base_bar() { return Accessor::base_bar(_instance_ref); }
private:
#define _instance_ref *static_cast<D*>(this) //D& derived() { return *(D*)this; }
After some I came with a solution that works event for private members of templated derived classes. It does not solves the problem of not exposing all the members of the derived class to the base, since it uses a friend declaration on the whole class. On the other hand, for the simple case, this does not requires repeating the base name, nor it's template parameters and will always work.
First the simple case when the derived is non-template. The base takes an additional void template parameter just to show that everything still works in the case of extra template parameters of the base. The only needed one, as per the CRTP, is the typename Derived.
//Templated variadic base
template <typename Derived, typename...>
struct Interface
{
using CRTP = Interface; //Magic!
void f() { static_cast<Derived*>(this)->f(); }
};
//Simple usage of the base with extra types
//This can only be used when the derived is NON templated
class A : public Interface<A, void>
{
friend CRTP;
void f() {}
};
The only thing needed for this to work is the using CRTP = Interface; declaration in the base and the friend CRTP; declaration in the derived.
For the case when the derived is itself templated the situation is trickier. It took me some time to come to the solution, and I'm sure it's still not perfect.
Most of the magic happens inside these templates:
namespace CRTP
{
template <template <typename, typename...> class _Base, typename _Derived, typename... _BaseArgs>
struct Friend { using Base = _Base<_Derived, _BaseArgs...>; };
template <template <typename, typename...> class _Base, typename ..._BaseArgs>
struct Base
{
template <template <typename...> class _Derived, typename... _DerivedArgs>
struct Derived : public _Base<_Derived<_DerivedArgs...>, _BaseArgs...> {};
};
}
Their usage is more or less straightforward. Two use the above templates several steps are needed.
First, when inheriting in the derived class the inherited-from base class, and it's optional parameters, needs to be given. This is done using CRTP::Base<MyBase, BaseOptional....>, where MyBase is the name of the class used for CRTP, and the BaseOptional... are template parameters that are passed to the base class as-is, directly after passing our derived class that is supplied in the next step. When the base class does not accepts any additional template parameters they can be omitted completely: CRTP::Base<MyBase>.
The next step is to introduce the derived class (the whole point of CRTP). This is done by following the above CRTP::Base<...> with a ::Derived<ThisDerived, DerivedOptional...>. Where ThisDerived is the class this is defined in, and DerivedOptional... are all the template parameters declared in this class'es template declaration. The optional parameters much be specified exactly as they appear in the class template declaration.
The last step is declaring the base class as a friend. This is done by declaring friend typename CRTP::Friend<MyBase, ThisDerived, BaseOptional...>::Base somewhere in the class. The BaseOptional... template perameters must be repeated exactly as they appear in the CRTP::Base<MyBase, BaseOptional...> that is inherited from.
Follows is an example of using a templated derived when the base does not depends on the templated types (but it still can take other template parameters, void in this example).
//Templated derived with extra, non-dependant types, passed to the base
//The arguments passed to CRTP::Base::Derived<, ARGS> must exactly match
// the template
template <typename T, typename... Args>
class B : public CRTP::Base<Interface, void>::Derived<B, T, Args...>
{
friend typename CRTP::Friend<Interface, B, void>::Base;
void f() {}
};
Next is an example for when the base depends on template parameters of the derived. The only difference from the previous example is the template keyword. An experiment shows that if the keyword is specified for the previous, non dependant, case the code also complies cleanly.
//Templated derived with extra dependant types passed to the base
//Notice the addition of the "template" keyword
template <typename... Args>
class C : public CRTP::Base<Interface, Args...>::template Derived<C, Args...>
{
friend typename CRTP::Friend<Interface, C, Args...>::Base;
void f() {}
};
Please note that these templates do not work for non-templated derived classes. I will update this answer when I find the solution, so a unified syntax could be used for all cases. The closest thing that can be done is just using some fake template parameter. Note that it still must be named and passed to the CRTP machinery. For example:
template <typename Fake = void>
class D : public CRTP::Base<Interface>::Derived<D, Fake>
{
friend typename CRTP::Friend<Interface, D>::Base;
void f() {}
};
Note that A, B, C & D are declared as class. That is, all their members are private.
Follows is some code that uses the above classes.
template <typename... Args>
void invoke(Interface<Args...> & base)
{
base.f();
}
int main(int, char *[])
{
{
A derived;
//Direct invocation through cast to base (derived.f() is private)
static_cast<A::CRTP &>(derived).f();
//Invocation through template function accepting the base
invoke(derived);
}
{
B<int> derived;
static_cast<B<int>::CRTP &>(derived).f();
invoke(derived);
}
{
C<void> derived;
static_cast<C<void>::CRTP &>(derived).f();
invoke(derived);
}
{
D<void> derived;
static_cast<D<>::CRTP &>(derived).f();
invoke(derived);
}
return 0;
}
The invoke free-standing templated function works for any class derived from the base.
Also shown is how to cast the derived to the base without the need to actually specify the name of the base.
Surprisingly, this does not depend on any system headers.
The full code is available here: https://gist.github.com/equilibr/b27524468a0519aad37abc060cb8bc2b
Comments and corrections are welcome.