具有交替类型的参数包

PeW*_*eWe 9 c++ parameters templates pack variadic-templates

我有一个struct C初始化的可变数量的实例struct Astruct B.例如:

struct A
{};

struct B
{};

struct C
{
    C(A&& o1, B&& p1, A&& o2)
    {}
    C(A&& o1, B&& p1, A&& o2, B&& p2, A&& o3)
    {}
    C(A&& o1, B&& p1, A&& o2, B&& p2, A&& o3, B&& p3, A&& o4)
    {}
    C(A&& o1, B&& p1, A&& o2, B&& p2, A&& o3, B&& p3, A&& o4, B&&p4, A&& o5)
    {}
};
Run Code Online (Sandbox Code Playgroud)

因此,我不想提供具有不同数量参数的多个ctor,而是希望找到一些通用的东西.但是,ctor参数的数量总是增加两个参数:B&&A&&.这可以使用参数包完成.或者是没有针对每个参数实现的另一个解决方案?

目标应该是struct C可以像下面的例子那样构建:

C c1 = { A(), B(), A() };
C c2 = { A(), B(), A(), B(), A(), B(), A() };
Run Code Online (Sandbox Code Playgroud)

等等

pal*_*asb 6

您可以使用可变参数模板和SFINAE来仅启用类型参数满足您(或任意)条件的构造函数.

#include <type_traits>
struct A {};
struct B {};
Run Code Online (Sandbox Code Playgroud)

你需要type_traitsstd::false_typestd::true_type.

alternates模板是关键.我们的目标是使alternates<X, Y, T1, T2, T3, ..., Tn>继承std::true_type,当且仅当T1,... Tn列表交替XY.默认选择(正下方)是没有的,但我们专门匹配的情况.

template <typename X, typename Y, typename... Ts>
struct alternates : std::false_type {};
Run Code Online (Sandbox Code Playgroud)

我选择使这个模板比你的要求更通用,并允许alternates<X, Y>继承true_type.空列表满足其所有元素交替的数学要求.这将是下面递归定义的一个很好的权宜之计.

template <typename X, typename Y>
struct alternates<X, Y> : std::true_type {};
Run Code Online (Sandbox Code Playgroud)

的任何其他列表alternates<X, Y, Ts...>交替当且仅当Ts...减去第一元件交替YX(Y第一!).

template <typename X, typename Y, typename... Ts>
struct alternates<X, Y, X, Ts...>
: alternates<Y, X, Ts...> {};

struct C
{
Run Code Online (Sandbox Code Playgroud)

我们将构造函数定义为首先获取参数包的模板(将推导出类型,不需要在调用时指定),并且它具有用于SFINAE目的的默认模板参数.如果无法基于参数包计算默认参数,则构造函数将不存在.我添加了关于我从示例中假设的对数的额外条件.

    template<typename... Ts,
        typename = typename std::enable_if<
            sizeof...(Ts) % 2 == 1 &&
            sizeof...(Ts) >= 3 && // did you imply this?
            alternates<A, B, Ts...>::value
        >::type>
    C(Ts&&...);
};
Run Code Online (Sandbox Code Playgroud)

SFINAE的工作方式是std::enable_if只定义std::enable_if<condition, T>::type(::type部分)if是否condition为真.这可以是在编译​​时可计算的任何布尔表达式.如果它是假的,::type那么最后说的是替换失败,并且你试图使用它的重载(例如C{A(), A(), A()})将不会被定义.

您可以测试以下示例是否按预期工作.评论出来的那些预计不起作用.

int main() {
    C c1 { A(), B(), A() };
    C c2 { A(), B(), A(), B(), A(), B(), A() };
    // C c3 {};                     // I assumed you need at least 2
    // C c4 { A(), B(), A(), A() }; // A, A doesn't alternate
    // C c5 { B(), A(), B() };      // B, A, B not allowed
    // C c6 { A(), B(), A(), B() }; // A, B, A, B doesn't pair
}
Run Code Online (Sandbox Code Playgroud)

在这里试试代码.


max*_*x66 5

我想你可以使用模板委托构造函数

事情如下

#include <utility>

struct A {};
struct B {};

struct C
 {
   C (A &&)
    { }

   template <typename ... Ts>
   C (A &&, B &&, Ts && ... ts) : C(std::forward<Ts>(ts)...)
    { }
 };

int main()
 {
   C(A{});
   C(A{}, B{}, A{});
   C(A{}, B{}, A{}, B{}, A{});
   C(A{}, B{}, A{}, B{}, A{}, B{}, A{});
 }
Run Code Online (Sandbox Code Playgroud)

如果你需要至少三个元素(因此C(A{})至少没有C(A{}, B{}, A{})),那么not-template构造函数就变成了

   C (A &&, B &&, A&&)
    { }
Run Code Online (Sandbox Code Playgroud)