2012-12-09 40 views
1

N有没有公共数据字段的不同类,只有方法(不重叠),如何通过boost预处理器创建unifiing所有代理类?如何创建代理类?

例如,我们有类:A有方法do();和B类有方法data();。我想知道是否有一种方法(例如使用Boost预处理器)来创建代理类,该代理类将具有来自A和B(此处为do()data())的所有方法,以及构造函数将指向该类实例的指针 - 一个用于A和一个对于B?

所以我们会得到API像这样的伪代码:

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(); 

是否有可能使用boost :: preprovcessor建立在C++ 11这样的事情,也可以是这样的东西已经在推动?

此外,如果这种事情是可能的使用外部发电机它可以适合我。

+2

我怀疑你需要使用解析和代码生成来自动完成此操作,但是如果这实际上可以使用C预处理器,我对这个答案很感兴趣。 –

回答

1

如果您不介意列出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<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) \ 
    } 

例如:

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; 
} 

的想法可以推广到多于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(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) \ 
    } 

用法:

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; 
} 
+0

顺便说一句,如果你能展示如何扩展定义'N'类的类型,它将如此炽热! Pleeease - 对于我们这些不太熟悉预处理器=) – myWallJSON

+0

有没有办法迭代类方法(不包括父类方法)? – myWallJSON

+0

我的主要问题,我不能编译它 - http://ideone.com/AlDoKA也没有在VS2012(输出吨失踪','之前'...') – myWallJSON