How to inherit a member function so that it always returns a reference to a derived instance?

I am working on a family of iterators, where all classes of iterators Xhave X& operator++() {++x; return *this}, so it seems appropriate to place it in a common base class. Unfortunately, the type of the return value changes because it must always return a reference to the derived class.

The problem is illustrated below. I would like it to f()work, but the only workarounds that I could come up with are g()and h()which are not satisfactory:

struct A {
    A& f() {return *this;}

    template <typename T>
    T& g() {return *(T*)this;}

    template <typename T>
    T& h(T& unused) {return *(T*)this;}
};

struct B : A {
    int x;
    B(int x) : x(x) {}
};

int main() {
    B b(12);

    //B b1 = b.f();   // error: conversion from 'A' to non-scalar type 'B' requested

    B b2 = b.g<B>();  // works
    B b3 = b.h(b);    // works
}

Is there any way to do the job B b1 = b.f();? Perhaps using the power of C ++ 11?

+4
3

CRTP:

template<class Derived>
struct A {
    Derived& f() {return static_cast<Derived&>(*this);}
};

struct B : A<B> {
    int x;
    B(int x) : x(x) {}
};
+13

F A, A B. .

    struct A {
  A& f() {return *this;}

  template <typename T>
  T& g() {return *(T*)this;}

  template <typename T>
  T& h(T& unused) {return *((T *)this);}
};

struct B : A {
  int x;
  B(int x) : x(x) {}
  B(const B & other) : x(other.x) {}
};

int main() {

  A  *b = new B(12);

  A *b1 = new B( (const B&)b->f());                                                                                 
  B b2 = b->g<B>();                                                                                                                                                                                 
  A b3 = B->h(*b);                                                                                                                                                             
}
0

@ecatmur , , , , CRTP . , 2 :

template <typename D>
struct A {
    D& f() {return *static_cast<D*>(this);}
};

template <typename D>
struct B : A<D> {
    int x;
    B(int x=0) : x(x) {}
};

struct C : B<C> {
    double y;
    C(double y=0.) : y(y) {}
};

int main() {
   C c(12.5);
   C c1 = c.f();   // works
}

, C, B:

int main() {
   B<B> b;   // error: type/value mismatch at argument 1 in template parameter list
}

, typename template, B. :

template <typename D=B> struct B : A<D> {};    // error

Thus, CRTP seems to be just a good idea in single inheritance situations.

I ended up with a simple solution to just return a reference to the base class A&. Since there is no loss of information in this way, derived classes can always discard the returned reference to the derived type:

struct A {
    A& f() {return *this;}
};

struct B : A {
    int x;
    B(int x=0) : x(x) {}
};

struct C : B {
    double y;
    C(double y=0.) : y(y) {}
};

int main() {
    B b(12);
    B b1 = (B&)b.f();  // works

    C c(12.5);
    C c1 = (C&)c.f();  // works
}

So, it seems right to just return the reference to the base class and, if necessary, add it to the derived classes.

0
source

Source: https://habr.com/ru/post/1543973/


All Articles