имеющий N
Разные классы, у которых нет открытых полей данных, только методы (которые не пересекаются), как создать их все прокси-классы через препроцессор boost?
Например, у нас были классы: A, который имел метод do();
и класс B имел метод data();
, Интересно, есть ли способ (например, с использованием Boost Preprocessor) создать прокси-класс, который бы имел все методы из 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();
Возможно ли создать такую вещь в C ++ 11, используя boost :: preprovcessor, или, может быть, такая вещь уже в 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;
}
Других решений пока нет …
Девушки по вызову в Санкт-Петербурге у метро: Проститутки Автово девушки легкого поведения