c++ - 如何创建代理类?

标签 c++ boost c++11 boost-preprocessor

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

例如,我们有类: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 中创建这样的东西,或者这样的东西可能已经在 boost 中了?

此外,如果使用外部生成器可以做到这一点,那对我来说没问题。

最佳答案

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

关于c++ - 如何创建代理类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13791083/

相关文章:

c++ - 如何在 GDI+ 中使用库存对象

c++ - boost::date_time 和 std::chrono 之间的互操作性

qt - QSplitter - 隐藏拆分器部分中包含的元素时,调整该部分的大小以仅适合可见内容

c++ - 一个简单的 C++11 宏

c++ - 具有可变模板参数的重载函数

c++ - 如何从 github 为 c++ 项目正确安装第三方库?

c++ - 拥有对象并为它们返回 ID 的数据结构

c++ - 学习C++,下一步是什么?还有什么是推荐的编译器?

c++ - 通过cmake禁用特定库的警告

c++ - boost::bind 返回一个函数对象,它是需要指针的函数的参数