C++ - is it possible to extract class and argument types from a member function type in a template?

前端 未结 4 1701
孤独总比滥情好
孤独总比滥情好 2021-02-15 18:19

I would like to wrap member functions that conform to the type \'void (ClassType::Function)(ArgType)\' with a templated class. Later, I want to pass an instance of ClassType to

4条回答
  •  猫巷女王i
    2021-02-15 18:49

    Reading over what you did made me think of a few options:

    1) Wrap the instantiation in inheritance. This moves the scary stuff to your definition.

    class FooWrapper : public Wrapper< double, Foo, &Foo::set >, public Foo
    {
    public:
        FooWrapper() : Wrapper(this){}
    };
    

    Your logic code would looks like this:

      FooWrapper fooWrapper;
      fooWrapper.do_something(1.0);
      std::cout << fooWrapper.get() << std::endl;
    

    Which means you didn't eliminate the double template arguments, you just moved them.

    2) There is a more generic way to wrap it, at one level:

      template
    class FooWrapper2 : public Wrapper, public classType1
    {
    public:
        FooWrapper2()
            : classType1(),
              Wrapper(this)
        {
    
        }
    };
    

    This way has the draw-back of more complicated looking logic, but you don't have to define a new wrapper every time, just a new wrapper for every signature:

      FooWrapper2 fooWrapper2;
      fooWrapper2.do_something(1.0);
      std::cout << fooWrapper2.get() << std::endl;
    

    3) Keeping in line with the template idea, you can wrap the wrapper:

      template
    class FooWrapper3 : public FooWrapper2
    {
    public:
        FooWrapper3()
        {
    
        }
    };
    

    The logic code from this looks a bit better, but you are stuck having to resubclass for each type you are wrapping (with specific code, instead of just using the template):

      FooWrapper3 fooWrapper3;
      fooWrapper3.do_something(1.0);
      std::cout << fooWrapper3.get() << std::endl;
    

    4) This option scraps the base wrapper class and uses an interface. Just pass the interfaces around as you would the wrappers and you can perform most actions.

    template   
    class Do_something {  
     public:  
    
      virtual void do_something(ArgType value) = 0;  
    
    };  
    
    template  
    class FooWrapper4 : public Foo, public Do_something  
    {  
    public:  
        virtual void do_something(ArgType value)  
        {  
            set(1.0);  
        }  
    };  
    

    The test program I played with:

    class Foo {
     public:
      Foo() : f_(0.0) {}
      void set(double v) { f_ = v * 2.1; }
      double get() { return f_; }
     private:
      double f_;
    };
    
    
    template 
    class Wrapper {
     public:
      explicit Wrapper(ClassType *cls) : cls_(cls) {}
    
      void do_something(ArgType value) {
        (cls_->*Method)(value);
      }
    
     private:
      ClassType *cls_;
    };
    
    
    class FooWrapper : public Wrapper< double, Foo, &Foo::set >, public Foo
    {
    public:
        FooWrapper() : Wrapper(this){}
    };
    
    
    template
    class FooWrapper2 : public Wrapper, public classType1
    {
    public:
        FooWrapper2()
            : classType1(),
              Wrapper(this)
        {
    
        }
    };
    
    template
    class FooWrapper3 : public FooWrapper2
    {
    public:
        FooWrapper3()
        {
    
        }
    };
    
    template 
    class Do_something {
     public:
    
      virtual void do_something(ArgType value) = 0;
    
    };
    
    template
    class FooWrapper4 : public Foo, public Do_something
    {
    public:
        virtual void do_something(ArgType value)
        {
            set(1.0);
        }
    };
    
    #include 
    int main(int argc, char ** argv) {
      Foo foo;
      Wrapper wrapper(&foo);
    
      wrapper.do_something(1.0);
      std::cout << foo.get() << std::endl;
    
      FooWrapper fooWrapper;
      fooWrapper.do_something(1.0);
      std::cout << fooWrapper.get() << std::endl;
      // outputs "2.1"
    
      FooWrapper2 fooWrapper2;
      fooWrapper2.do_something(1.0);
      std::cout << fooWrapper2.get() << std::endl;
    
      FooWrapper3 fooWrapper3;
      fooWrapper3.do_something(1.0);
      std::cout << fooWrapper3.get() << std::endl;
    
      FooWrapper4 fooWrapper4;
      fooWrapper4.do_something(1.0);
      std::cout << fooWrapper4.get() << std::endl;
    
      return 0;
    }
    

提交回复
热议问题