将CTAD与多个模板参数包一起应用

问题描述 投票:1回答:1

按照此处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;
}
c++ templates c++17 variadic-templates
1个回答
0
投票

首先,在使用示波器分辨率运算符时不会完成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<Args1...>& b1Bar2<Args2...>& b2用作非const左值引用,但是为它们提供了prvalue。非const左值引用无法绑定到右值,因此会出现错误。要么按参数取值,要么按const左值引用。


最后,您将得到一个错误,指出_b1_b2没有默认构造函数,这是正确的。它们是必需的,因为您是在构造函数中默认初始化_b1_b2。您稍后才为它们分配值。

因此,将默认构造函数添加到Bar1Bar2或更好地使用初始化代替赋值:

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

完成所有这些步骤后,应编译代码。我不确定您的目标是[[exactly,所以不能完全确定这是否会满足您的要求。

© www.soinside.com 2019 - 2024. All rights reserved.