【问题标题】:Applying CTAD with multiple template parameter packs将 CTAD 与多个模板参数包一起应用
【发布时间】:2020-03-18 08:30:46
【问题描述】:

按照How can I have multiple parameter packs in a variadic template? 此处提供的一些解决方案,我希望将多个参数包应用于一个类并使用 CTAD 使该类更可用。

这是我想出的(在Coliru),但这给出了:

错误:类模板参数推导失败

这是我试过的代码:

// A template to hold a parameter pack
template < typename... >
struct Typelist {};

// Declaration of a template
template< typename TypeListOne 
        , typename TypeListTwo
        > 
struct Foo;     

// A template to hold a parameter pack
template <typename... Args1, typename... Args2>
struct Foo< Typelist < Args1... >
                 , Typelist < Args2... >
                 >{
    template <typename... Args>
    struct Bar1{
        Bar1(Args... myArgs) {
            _t = std::make_tuple(myArgs...);
        }
        std::tuple<Args...> _t;
    };

    template <typename... Args>
    struct Bar2{
        Bar2(Args... myArgs) {
            _t = std::make_tuple(myArgs...);
        }
        std::tuple<Args...> _t;
    };

    Bar1<Args1...> _b1;
    Bar2<Args2...> _b2;

    Foo(Bar1<Args1...>& b1, Bar2<Args2...>& b2) {
        _b1 = b1;
        _b2 = b2;
    }
};

int main()
{

    Foo{Foo::Bar1(1, 2.0, 3), Foo::Bar2(100, 23.4, 45)};
    return 0;
}

【问题讨论】:

  • 恕我直言,即使有演绎指南,编译器也无法理解Foo::Bar1(1, 2.0, 3)

标签: c++ templates c++17 variadic-templates


【解决方案1】:

首先,使用范围解析运算符时不会执行 CTAD,因此永远不能使用 Foo::。您必须明确指定此 Foo 的模板参数。

我建议您只需将Bar1Bar2 移到Foo 部分特化之外的名称空间范围并使用

Foo{Bar1(1, 2.0, 3), Bar2(100, 23.4, 45)};

改为。


然后会报Foo的扣法失败。这是因为只有 primary 模板中的构造函数被考虑用于隐式推导指南。但是您要使用的构造函数在部分特化中,而不是主模板。

因此您需要自己添加适当的扣除指南,例如:

template <typename... Args1, typename... Args2>
Foo(Bar1<Args1...>, Bar2<Args2...>) -> Foo<Typelist<Args1...>, Typelist<Args2...>>;

然后你会得到一个没有构造函数是可行的错误。这是因为您将Bar1&lt;Args1...&gt;&amp; b1Bar2&lt;Args2...&gt;&amp; b2 作为非const 左值引用,但您为它们提供了纯右值。非const 左值引用无法绑定到右值,因此会出现错误。通过值或const 左值引用获取参数。


最后你会得到_b1_b2没有默认构造函数的错误,这是真的。它们是必需的,因为您在构造函数中默认初始化 _b1_b2。您只能在以后为它们分配值。

因此,要么将默认构造函数添加到 Bar1Bar2,要么更好地使用初始化而不是赋值:

Foo(const Bar1<Args1...>& b1, const Bar2<Args2...>& b2) : _b1(b1), _b2(b2) { }

完成所有这些步骤后,代码应该可以编译。我不确定你的目标是什么确切,所以不完全确定这是否会达到你想要的效果。

【讨论】:

猜你喜欢
  • 2020-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-30
  • 1970-01-01
  • 2020-07-19
  • 2023-04-07
  • 1970-01-01
相关资源
最近更新 更多