如何创建代理类? [英] How to create proxy class?

查看:169
本文介绍了如何创建代理类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

N 不具有公共数据字段,只有方法(不重叠),如何创建统一他们所有的代理类通过boost预处理器? p>

例如,我们有类:方法 do(); ,类B有方法 data(); 。我想知道是否有一种方法(例如使用Boost Preprocessor)创建一个代理类,将所有的方法从A和B(这里 do() data())和一个构造函数接受那个类实例的指针 - 一个用于A,一个用于B?



(A,B,C); //或者如果需要JOIN(path_to_A。)。 h,path_to_B.h,C)
// ...
A * a = new A();
B * b = new B();
C * c = new C(a,b);
c-> data();
c-> do();

可以使用boost :: preprovcessor在C ++ 11中创建这样的东西,事情已经在提升?



如果这样的事情可能使用外部生成器,它会为我确定。

解决方案

如果你不介意列出A和B中的所有方法,我们可以使用SFINAE。这里的关键是我们定义两个方法 C :: data(),它转发给每个 A :: data() B :: data()。编译器将过滤掉不能编译的那个,因此我们可以将它转发给正确的成员。

  #include< type_traits> 
#include< boost / preprocessor / seq / for_each.hpp>

#define CALLER_NAME(method_name)BOOST_PP_CAT(BOOST_PP_CAT(_,method_name),_caller__)

#define GEN_CALLER(r,ignored,method_name)\
template < typename K,typename ... T> \
static auto CALLER_NAME(method_name)(K * k,T& ... args) - > decltype(k-> method_name(std :: forward< T>(args)...)){\
return k-> method_name(std :: forward& ); \
} \
template< typename ... T> \
auto method_name(T&& ... args) - > decltype(CALLER_NAME(method_name)(_ first__,std :: forward< T>(args)...)){\
return CALLER_NAME(method_name)(_ first__,std :: forward< T>(args)。 ..); \
} \
template< typename ... T> \
auto method_name(T&& ... args) - > decltype(CALLER_NAME(method_name)(_ second__,std :: forward< T>(args)...)){\
return CALLER_NAME(method_name)(_ second__,std :: forward< T>(args)。 ..); \
}

#define JOIN(FIRST,SECOND,NAME,METHODS)\
struct C {\
FIRST * _first__; \
SECOND * _second__; \
NAME(FIRST * _first__,SECOND * _second__):_first __(_ first__),_second __(_ second__){} \
BOOST_PP_SEQ_FOR_EACH(GEN_CALLER,,METHODS)\
}

例如:

  struct A {
int x;

void a(){
std :: cout< an a!<< x < \\\
;
}
};

struct B {
double x;

double b(double k){
std :: cout< b!<< x < ,< k<< \\\
;
return x - k;
}

void b(){
std :: cout< b!<< x < ,?\\\
;
}
};

JOIN(A,B,C,(a)(b));

int main(){
A a {12};
B b {24};

C c(& a,& b);

c.a();
c.b();
std :: cout<< c.b(2445)<< std :: endl;
}






到超过2个类别:

  #include< type_traits& 
#include< boost / preprocessor / seq / for_each.hpp>
#include< boost / preprocessor / seq / for_each_i.hpp>
#include< boost / preprocessor / punctuation / comma_if.hpp>

#define CALLER_NAME(method_name)\
BOOST_PP_CAT(BOOST_PP_CAT(_caller_,method_name),__)
#define FIELD_NAME(ClassName)\
BOOST_PP_CAT (_field_,ClassName),__)
#define INVOKER_IMPL(method_name,ClassName)\
CALLER_NAME(method_name)(FIELD_NAME(ClassName),std :: forward< T>(args)...)
#define CALLER_IMPL(method_name)\
k-> method_name(std :: forward< T>(args)...)
#define FORWARD(IMPL) decltype(IMPL){return IMPL; }

#define GEN_INVOKER(r,method_name,i,ClassName)\
template< typename ... T> \
auto method_name(T& ... args)\
FORWARD(INVOKER_IMPL(method_name,ClassName))

#define GEN_CALLER(r,ALL_CLASSES,method_name )\
private:\
template< typename K,typename ... T> \
static auto CALLER_NAME(method_name)(K * k,T& ... args)\
FORWARD(CALLER_IMPL(method_name))\
public:\
BOOST_PP_SEQ_FOR_EACH_I_R(r,GEN_INVOKER,method_name,ALL_CLASSES)

#define GEN_FIELD(r,IGNORED,ClassName)\
ClassName * FIELD_NAME(ClassName);
#define GEN_ARG(r,IGNORED,i,ClassName)\
BOOST_PP_COMMA_IF(i)ClassName * FIELD_NAME(ClassName)
#define GEN_CTOR(r,IGNORED,i,ClassName)\
BOOST_PP_COMMA_IF(i)FIELD_NAME(ClassName)(FIELD_NAME(ClassName))

#define JOIN(ALL_CLASSES,ClassName,METHODS)\
struct ClassName {\
private:\
BOOST_PP_SEQ_FOR_EACH(GEN_FIELD,,ALL_CLASSES)\
public:\
ClassName(BOOST_PP_SEQ_FOR_EACH_I(GEN_ARG,,ALL_CLASSES))\
:BOOST_PP_SEQ_FOR_EACH_I(GEN_CTOR ,,ALL_CLASSES){} \
BOOST_PP_SEQ_FOR_EACH(GEN_CALLER,ALL_CLASSES,METHODS)\
}


b $ b

用法:

  struct A {
int x;

void a(){
std :: cout< an a!<< x < \\\
;
}
};

struct B {
double x;

double b(double k){
std :: cout< b!<< x < ,< k<< \\\
;
return x - k;
}

void c(){
std :: cout< b!<< x < ,?\\\
;
}
};

struct C {
double x;

double c(double k){
std :: cout< c!<< x < ,< k<< \\\
;
return x + k;
}

void b(){
std :: cout< c!<< x < ,?\\\
;
}
};


JOIN((A)(B)(C),D,(a)(b)(c));

int main(){
A a {12};
B b {24};
C c {36};

D d {& a,& b,& c};

d.a();
d.b();
d.c();
std :: cout<< d.b(48)<< std :: endl;
std :: cout<< d.c(64)<< std :: endl;
}


Having N difrent classes that have no public data fields, only methods (that do not overlap), how to create unifiing them all proxy class via boost preprocessor?

For example we had classes: A that had method do(); and class B had method data();. I wonder if there is a way (using Boost Preprocessor for example) to create a proxy class that would have all methods from A and B (here do() data()) and a constructor taking in that pointers to that classes instances - one for A and one for B?

So we would get api like such pseudocode:

JOIN(A, B, C);// or if needed JOIN("path_to_A.h", "path_to_B.h", C)
//...
A * a = new A();
B * b = new B();
C * c = new C(a, b);
c->data();
c->do();

Is it possible to create such thing in C++11 using boost::preprovcessor or may be such thing is already in boost?

Also if such thing is possible using external generator it'll be ok for me.

解决方案

If you don't mind listing all methods in A and B, we could do it with SFINAE. The essense here is that we define two methods C::data() which forward to each of A::data() and B::data(). The compiler will filter out the one which cannot be compiled, thus we could forward it to the correct member.

#include <type_traits>
#include <boost/preprocessor/seq/for_each.hpp>

#define CALLER_NAME(method_name) BOOST_PP_CAT(BOOST_PP_CAT(_, method_name), _caller__)

#define GEN_CALLER(r, ignored, method_name) \
    template <typename K, typename... T> \
    static auto CALLER_NAME(method_name)(K* k, T&&... args) -> decltype(k->method_name(std::forward<T>(args)...)) { \
        return k->method_name(std::forward<T>(args)...); \
    } \
    template <typename... T> \
    auto method_name(T&&... args) -> decltype(CALLER_NAME(method_name)(_first__, std::forward<T>(args)...)) { \
        return CALLER_NAME(method_name)(_first__, std::forward<T>(args)...); \
    } \
    template <typename... T> \
    auto method_name(T&&... args) -> decltype(CALLER_NAME(method_name)(_second__, std::forward<T>(args)...)) { \
        return CALLER_NAME(method_name)(_second__, std::forward<T>(args)...); \
    }

#define JOIN(FIRST, SECOND, NAME, METHODS) \
    struct C { \
        FIRST* _first__; \
        SECOND* _second__; \
        NAME(FIRST* _first__, SECOND* _second__) : _first__(_first__), _second__(_second__) {} \
        BOOST_PP_SEQ_FOR_EACH(GEN_CALLER, , METHODS) \
    }

For example:

struct A {
    int x;

    void a() {
        std::cout << "an a! " << x << "\n";
    }
};

struct B {
    double x;

    double b(double k) {
        std::cout << "b! " << x << ", " << k << "\n";
        return x - k;
    }

    void b() {
        std::cout << "b! " << x << ", ?\n";
    }
};

JOIN(A, B, C, (a)(b));

int main() {
    A a {12};
    B b {24};

    C c (&a, &b);

    c.a();
    c.b();
    std::cout << c.b(2445) << std::endl;
}


The idea could be generalized to more than 2 classes:

#include <type_traits>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>

#define CALLER_NAME(method_name) \
    BOOST_PP_CAT(BOOST_PP_CAT(_caller_, method_name), __)
#define FIELD_NAME(ClassName) \
    BOOST_PP_CAT(BOOST_PP_CAT(_field_, ClassName), __)
#define INVOKER_IMPL(method_name, ClassName) \
    CALLER_NAME(method_name)(FIELD_NAME(ClassName), std::forward<T>(args)...)
#define CALLER_IMPL(method_name) \
    k->method_name(std::forward<T>(args)...)
#define FORWARD(IMPL) -> decltype(IMPL) { return IMPL; }

#define GEN_INVOKER(r, method_name, i, ClassName) \
    template <typename... T> \
    auto method_name(T&&... args) \
        FORWARD(INVOKER_IMPL(method_name, ClassName))

#define GEN_CALLER(r, ALL_CLASSES, method_name) \
private: \
    template <typename K, typename... T> \
    static auto CALLER_NAME(method_name)(K* k, T&&... args) \
        FORWARD(CALLER_IMPL(method_name)) \
public: \
    BOOST_PP_SEQ_FOR_EACH_I_R(r, GEN_INVOKER, method_name, ALL_CLASSES)

#define GEN_FIELD(r, IGNORED, ClassName) \
    ClassName* FIELD_NAME(ClassName);
#define GEN_ARG(r, IGNORED, i, ClassName) \
    BOOST_PP_COMMA_IF(i) ClassName* FIELD_NAME(ClassName)
#define GEN_CTOR(r, IGNORED, i, ClassName) \
    BOOST_PP_COMMA_IF(i) FIELD_NAME(ClassName)(FIELD_NAME(ClassName))

#define JOIN(ALL_CLASSES, ClassName, METHODS) \
    struct ClassName { \
    private: \
        BOOST_PP_SEQ_FOR_EACH(GEN_FIELD, , ALL_CLASSES) \
    public: \
        ClassName(BOOST_PP_SEQ_FOR_EACH_I(GEN_ARG, , ALL_CLASSES)) \
            : BOOST_PP_SEQ_FOR_EACH_I(GEN_CTOR, , ALL_CLASSES) {} \
        BOOST_PP_SEQ_FOR_EACH(GEN_CALLER, ALL_CLASSES, METHODS) \
    }

Usage:

struct A {
    int x;

    void a() {
        std::cout << "an a! " << x << "\n";
    }
};

struct B {
    double x;

    double b(double k) {
        std::cout << "b! " << x << ", " << k << "\n";
        return x - k;
    }

    void c() {
        std::cout << "b! " << x << ", ?\n";
    }
};

struct C {
    double x;

    double c(double k) {
        std::cout << "c! " << x << ", " << k << "\n";
        return x + k;
    }

    void b() {
        std::cout << "c! " << x << ", ?\n";
    }
};


JOIN((A)(B)(C), D, (a)(b)(c));

int main() {
    A a {12};
    B b {24};
    C c {36};

    D d {&a, &b, &c};

    d.a();
    d.b();
    d.c();
    std::cout << d.b(48) << std::endl;
    std::cout << d.c(64) << std::endl;
}

这篇关于如何创建代理类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆