Я пытаюсь переслать ряд параметров в два разных класса mixin следующим образом:
template <typename... Checkers>
class Checker : public Checkers... {
public:
template<typename... Args>
Checker(Args&&... args) : Checkers(std::forward<Args>(args))... { }
};
template <typename... Handlers>
class Handler : public Handlers... {
public:
template <typename... Args>
Handler(Args&&... args) : Handlers(std::forward<Args>(args))... { }
};
template <typename C, typename H>
class Tester : public C, H {
public:
template <typename... ArgC, typename... ArgH>
Tester(std::tuple<ArgC...>&& argc, ArgH&&... argh) : C(argc), H(argh...) {
}
};
Checker и Handler — это две разные коллекции классов Mixin с различными требованиями для каждого, но общими требованиями для всех участников. Я понимаю, что не могу создать двойную переменную конструкцию в Tester (компилятор не может определить, где разделить аргументы, поэтому передает их все в Handler, а не в Checker), поэтому я передаю аргументы Checker в Tuple и аргументы Handler в вариационный список. Проблема в том, что конструктор Checker отвечает за пересылку этих параметров в свои базы. Обработчик может сделать это, потому что конструктор обработчика является списком с переменными числами, но Checker получает кортеж, но вы не можете для каждого перенаправлять элементы кортежа, такие как forward, с помощью списка параметров с переменным числом.
Любой совет будет принята с благодарностью. Благодарю.
дополнительный
Решением будет либо а) распаковать argc
в Checker
Вариантный конструктор или б) Сделать Checker
конструктор берет кортеж и затем каким-то образом пересылает каждый элемент этого кортежа каждому из Checker
смешанные основы, Checkers...
, я понимаю std::pair
есть хитрость для пересылки кортежа в виде списка фиксированных аргументов его типам, таким как 3-параметрический std::vector
конструктор, использующий std::piecewise_construct
введите маркер, чтобы сообщить об этом, чтобы распаковать, но я не вижу, как это можно применить здесь. Я посмотрел на реализацию GCC 4.8.1 std::pair
с std::piecewise_construct
и не мог понять это. Я прочитал некоторые из старых, до C ++ 11 книг по шаблонному метапрограммированию (Современный дизайн C ++ а также Шаблон метапрограммирования на С ++, например) но сейчас я в недоумении, потому что есть стандарт, и я пытаюсь избежать Boost и Loki.
дополнительный
Должен соответствовать по крайней мере GCC 4.7.2. Решение, которое я нашел на основе std::pair
требует Наследование конструктора, который не стал доступен до GCC 4.8.1 который не поддерживается в моей системе сборки.
дополнительный
Хотя GCC 4.6.3 поддержка была бы хорошей, Делегированные Конструкторы были добавлены в 4.7.2, поэтому я должен иметь доступ к этой языковой функции.
http://cpptruths.blogspot.fr/2012/06/perfect-forwarding-of-parameter-groups.html
Решение Davidbrcz, как указано в его блоге выше, было достаточно, чтобы решить мою головоломку. Решение довольно сложное, поэтому я направлю вас на его страницу для этого, но основная идея заключается в том, чтобы на лету создать кортеж числового индекса, как la std :: maketuple (0, 1, 2, … ) где кортеж содержит каждый из индексов различных членов кортежа, которые вы должны перечислить. Тогда вы просто используете:
M(std::forward<ArgM>(std::get<IdxM>(argm))...)
Для M в качестве C или H в приведенном выше примере и ArgM аргументы для M и IdxM — кортеж индексов одинакового размера. Поскольку списки имеют одинаковую длину, список сворачивается в параметры в тандеме, а кортеж распаковывается.
Ограничение заключается в том, что вы хотите, чтобы сложный шаг построения кортежа индекса был скрыт как деталь реализации, вам нужно использовать Constructor Delegation, чтобы общедоступный конструктор брал 2 кортежа, которые затем делегировали частному конструктору, который принимает 2 кортежа значений и 2 индексных кортежа. GCC 4.7.2 поддерживает делегированные конструкторы, но 4.6.3 — нет.
Чтобы обойти это, вам нужно сделать конструктор с 4 параметрами (2 кортежа значений, 2 кортежа индексов) общедоступным, а затем я написал макрос для заполнения параметров кортежа индекса:
#if __GNUC__ < 4 || __GNUC_MINOR__ <= 6
#define ZEROPARAM , detail::make_indices<>::type()
#define ONEPARAM , detail::make_indices<int>::type()
#define TWOPARAM , detail::make_indices<int, int>::type()
#define THREEPARAM , detail::make_indices<int, int, int>::type()
#define FOURPARAM , detail::make_indices<int, int, int, int>::type()
#define FIVEPARAM , detail::make_indices<int, int, int, int, int>::type()
#define SIXPARAM , detail::make_indices<int, int, int, int, int, int>::type()
#define SEVENPARAM , detail::make_indices<int, int, int, int, int, int, int>::type()
#define EIGHTPARAM , detail::make_indices<int, int, int, int, int, int, int, int>::type()
#define NINEPARAM , detail::make_indices<int, int, int, int, int, int, int, int, int>::type()
#define TENPARAM , detail::make_indices<int, int, int, int, int, int, int, int, int, int>::type()
#else // __GNUC__ < 4 || __GNUC_MINOR__ <= 6
#define ZEROPARAM
#define ONEPARAM
#define TWOPARAM
#define THREEPARAM
#define FOURPARAM
#define FIVEPARAM
#define SIXPARAM
#define SEVENPARAM
#define EIGHTPARAM
#define NINEPARAM
#define TENPARAM
#endif // __GNUC__ < 4 || __GNUC_MINOR__ <= 6
А затем добавьте соответствующий макрос, следуя конструкции данного тестера, по крайней мере, пока в GCC 4.6.3 все еще есть люди, пока я работаю над тем, чтобы все получили как минимум 4.7.2 и предпочтительно 4.8.1. 🙂
Я хотел бы отдать должное Davidbrcz за решение, но по крайней мере это может быть полезно для людей, сталкивающихся с подобной проблемой, для применения его решения в их конкретном случае. Главное — скопировать его класс шаблона make_indices, чтобы выполнить реальную работу; остальное — прогулка по пирогу!
Других решений пока нет …