4

我正在尝试将一系列参数转发到两个不同的 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 的构造函数负责将这些参数转发到它的基础。Handler 可以这样做,因为 Handler 的构造函数是一个可变参数列表,但是 Checker 得到一个元组但你不能 for-each 转发一个元组的元素,比如 forward 可以是一个可变参数列表。

任何建议将不胜感激。谢谢。

额外的

一个解决方案是 a) 解压argcChecker的可变参数构造函数中,或者 b) MakeChecker的构造函数采用一个元组,然后以某种方式将该元组的每个元素转发到每个Checkermixin 基Checkers...。我意识到std::pair有一个技巧可以将元组作为固定参数列表转发到它的类型,例如std::vector使用类型标记的 3 参数构造函数std::piecewise_construct来通知它进行解包,但我不知道如何在这里应用它。我查看了 GCC 4.8.1 的std::pairwith实现,std::piecewise_construct但无法弄清楚。我阅读了一些关于模板元编程的较早的 C++11 之前的书籍(现代 C++ 设计C++ 模板元编程,例如),但现在有一个标准,我在这里不知所措,我试图避免使用 Boost 和 Loki。

额外的

必须至少符合GCC 4.7.2。我找到的解决方案std::pair需要Constructor Inheritance,直到GCC 4.8.1才可用,我的构建系统不支持它。

额外的

尽管对GCC 4.6.3的支持会很好,但在 4.7.2 中添加了委托构造函数,因此我应该可以访问该语言功能。

4

1 回答 1

2

http://cpptruths.blogspot.fr/2012/06/perfect-forwarding-of-parameter-groups.html

Davidbrcz 在上面的博客中指定的解决方案足以解决我的难题。该解决方案相当复杂,因此我将引导您访问他的页面,但基本思想是即时创建一个数字索引元组,例如 std::maketuple(0, 1, 2, ... ) 其中元组包含您需要枚举的元组的各个成员的每个索引。然后你只需使用:

M(std::forward<ArgM>(std::get<IdxM>(argm))...)

对于上面示例中的 M 作为 C 或 H 和 ArgM,M 和 IdxM 的参数是相同大小的索引元组。因为列表的长度相同,所以列表被串联到参数中,并且元组被解包。

限制是因为您希望将构建索引元组的复杂步骤隐藏为实现细节,您需要使用构造函数委托,以便公共构造函数获取 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模板类来做实际的工作;剩下的就是小菜一碟了!

于 2014-03-06T20:06:12.133 回答