简体   繁体   中英

How to write a wrapper that keeps rapping the output?

Basically, what I want to do is to hava a wrapper on some abstract class, then have the same wrapper class wrap around the output of any member function of that class. Keep doing that so that all objects are always wrapped.

Like (presudocode)

wrap<set(1..10)> (multiply,2)
                 (divide,3)
                 (plus,5)
                 (inverse)
                 (collect first 10)
                .unwrap()

All lines above except the last line outputs wrap of something. It seems to be meanling less for now, but I believe then we can apply interesting things on it like:

wrap<someClass> dat;
dat.splitIntoThreads(2)
    (thingA)    .clone()
    (thingB)    (thing1)
    (thingC)    (thing2)
    (thingD)    (thing3)
    .nothing()  (thing4)
    .sync()     .exit()
    .addMerge()

Here is my code for wrap:

template<class T>
struct wrap{
  wrap(){}
  wrap(T b){a=b;}
  template<class L,class...R>
  L operator() (L(T::*f)(R...),R...r){
    return a.f(r...);
  }
  T a;
};

int main(){
  wrap<testClass> a;
  a(&testClass::f,13,'a');
}

It's working (gcc, c++0x). But when I replace the 6,7th line with the following (to actually wrap the result)

wrap<L> operator() (L(T::*f)(R...),R...r){
  return wrap<L>(a.f(r...));

The compiler just sais: creating pointer to member function of non-class type "int".

How can I fix this? Is there any better to do this? Inheritence is one way but since we might have variable instance in one wrap, I think it's not useful.

EDIT

Here's my test class

struct testClass{
  int f(int a,char b){
    return a+b;
  }
};

The reason why I'm using wrap L instead of wrap T is that the return type might not always be T.

You can try something like this:

#include <iostream>
#include <type_traits>

template<class T, bool = false>
struct wrap{
  template <typename... Args>
  wrap(Args&&... args) : a{std::forward<Args>(args)...} {};
  template<class L, class...R>
  wrap<L,std::is_fundamental<L>::value> operator() (L(T::*f)(R...),R...r){
    return wrap<L,std::is_fundamental<L>::value > {(a.*f)(r...)};
  }
  T a;
};

template<class T>
struct wrap <T,true>{
  template <typename... Args>
  wrap(Args&&... args) : a{std::forward<Args>(args)...} {}
  template<class L, class...R>
  wrap<L,std::is_fundamental<L>::value> operator() (L(*f)(T a, R...), R...r){
      return wrap<L,std::is_fundamental<L>::value > {f(a, r...)};
  }
  T a;
};

class testClass {
    int m;
public:
testClass(int _m) : m{_m}{}
    int multiAdd(int x, char y) {
        m += x + y;
        return m;
    }
};

int add(int a, char b)
{
    return a+b;
}

int main(){
  wrap<testClass> a{0};
  std::cout << a(&testClass::multiAdd,0,'d')(add,'a').a<<std::endl;

  wrap<int, true> b{3};
  std::cout << b(add,'a').a<<std::endl;
}

cpp.sh/6icg

It seems the error is in your testclass definition. Please check the below example.

Also, wrap in the operator() can be returned as reference. I don't see any need to create temporaries to be used for () chaining.

template<class T>
struct wrap{
  template <typename... Args>
  wrap(Args&&... args) : a{std::forward<Args>(args)...} {};

  template<class L, class...R>
  wrap<T>& operator() (L(T::*f)(R...),R...r){
    a.f(r...);
    return *this; //returning reference to current wrap object.
  }
  T a;
};

A test class to accumulate numbers.

class testClass {
    int m;
public:
testClass(int _m) : m{_m}{}
    int f(int x) {
        m += x;
        std::cout << ' ' << m;
        return m;
    }
};

An usage example:

int main(){
  wrap<testClass> a{0};
  a(&testClass::f,13)(&testClass::f, 11)(&testClass::f,3)(&testClass::f, 21);
}

Output of sum accumulated at each step:

13 24 27 48

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM