Search code examples
c++boostc++11boost-mplboost-preprocessor

C++11 how to proxy class function having only its name and parent class?


I wonder if it is possible using boost::mpl/preprocessor or some noce C++11 features to create function proxy from class type and function name.

Say we had:

  inline void set_email(const ::std::string& value);
  inline void set_email(const char* value);

inside class Email. We know there is set_email function n it, we want to create a prox class with API like

PROXY(Email, set_email, MyEmail)

Email * email = new Email();
MyEmail * myEmail = new MyEmail(email);

and have abilety to call any of set_email overloads.Is it possible and how to create such class that would proxy any number of overload functions not knowing there types (only names)?


Solution

  • How about this:

    proxy_macro.hpp

    #include <type_traits>
    #include <utility>
    
    #define PROXY(proxified, member_function, proxy_name)                                                                           \
      class proxy_name                                                                                                              \
      {                                                                                                                             \
      private:                                                                                                                      \
        proxified & ref_;                                                                                                           \
                                                                                                                                    \
      public:                                                                                                                       \
        proxy_name(proxified &ref)                                                                                                  \
          : ref_(ref)                                                                                                               \
          {                                                                                                                         \
          }                                                                                                                         \
                                                                                                                                    \
        /* general version */                                                                                                       \
        template<typename ... Args>                                                                                                 \
        auto member_function(Args&& ... args)                                                                                       \
        -> typename std::enable_if<!std::is_void<decltype(ref_.member_function(std::forward<Args>(args)...))>::value,               \
                                   decltype(ref_.member_function(std::forward<Args>(args)...))>::type                               \
          {                                                                                                                         \
            return (ref_.member_function(std::forward<Args>(args)...));                                                             \
          }                                                                                                                         \
                                                                                                                                    \
        /* void return type version */                                                                                              \
        template<typename ... Args>                                                                                                 \
        auto member_function(Args&& ... args)                                                                                       \
        -> typename std::enable_if<std::is_void<decltype(ref_.member_function(std::forward<Args>(args)...))>::value,                \
                                   void>::type                                                                                      \
          {                                                                                                                         \
            ref_.member_function(std::forward<Args>(args)...);                                                                      \
          }                                                                                                                         \
                                                                                                                                    \
      };
    

    This compiles and work fine for me on g++ 4.7:

    #include "proxy_macro.hpp"
    
    #include <iostream>
    #include <string>
    
    class   Email
    {
    public:  
      void set_email(const ::std::string& value)
      {
        std::cout << value << std::endl;
      }
    
      void set_email(const char* value)
      {
        std::cout << value << std::endl;
      }
    
      int   set_email()
      {
        return (42);
      }
    
    };
    
    PROXY(Email, set_email, MyEmail)
    
    int main(void)
    {
      Email   mail;
      MyEmail my_mail(mail);
    
      std::string str = "test string";
      const char * ptr = "test char pointer";
    
      my_mail.set_email(str);
      my_mail.set_email(ptr);
    
      std::cout << "test return: " << my_mail.set_email() << std::endl;
    
      return (0);
    }
    

    Edit (smaller version thanks to comments)

    proxy_macro.hpp

    #include <type_traits>
    #include <utility>
    
    #define PROXY(proxified, member_function, proxy_name)                \
      class proxy_name                                                   \
      {                                                                  \
      private:                                                           \
        proxified & ref_;                                                \
                                                                         \
      public:                                                            \
        proxy_name(proxified &ref)                                       \
          : ref_(ref)                                                    \
          {                                                              \
          }                                                              \
                                                                         \
        template<typename ... Args>                                      \
        auto member_function(Args&& ... args)                            \
        -> decltype(ref_.member_function(std::forward<Args>(args)...))   \
          {                                                              \
            return (ref_.member_function(std::forward<Args>(args)...));  \
          }                                                              \
      };