Применение CTAD с несколькими пакетами параметров шаблона - PullRequest
2 голосов
/ 18 марта 2020

Следуя некоторым решениям, представленным здесь Как я могу иметь несколько пакетов параметров в шаблоне c variadi? , я надеюсь применить несколько пакетов параметров к классам и использовать 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;
}

1 Ответ

5 голосов
/ 18 марта 2020

Во-первых, CTAD не выполняется при использовании оператора разрешения контекста, поэтому Foo:: никогда не может использоваться. Вы должны явно указать аргументы шаблона для этого Foo.

Я предлагаю просто переместить Bar1 и Bar2 за пределы частичной специализации Foo в область пространства имен и использовать

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

вместо.


Тогда вы получите ошибку, что вычет для Foo не удастся. Это потому, что только конструкторы в первичном шаблоне рассматриваются для неявных руководств по выводам. Но конструктор, который вы хотите использовать, относится к частичной специализации, а не к первичному шаблону.

Поэтому вам нужно самостоятельно добавить соответствующее руководство по выводам, например:

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

Тогда вы получите ошибку, что ни один конструктор не является жизнеспособным. Это связано с тем, что вы берете Bar1<Args1...>& b1 и Bar2<Args2...>& b2 в качестве не const lvalue ссылок, но вы предоставляете их значения. Ссылки, отличные от const lvalue, не могут быть привязаны к rvalues, поэтому вы получаете сообщение об ошибке. Либо принимайте параметры по значению, либо по const lvalue reference.


Наконец, вы получите ошибку, что _b1 и _b2 не имеют конструкторов по умолчанию, что верно. Они необходимы, потому что вы инициализируете по умолчанию _b1 и _b2 в своем конструкторе. Вы только потом присваиваете им значения.

Так что либо добавьте конструкторы по умолчанию к Bar1 и Bar2, либо лучше используйте инициализацию вместо присваивания:

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

После всех этих шагов код должен скомпилироваться. Я не уверен, что именно точно ваша цель, поэтому не совсем уверен, будет ли это делать то, что вы хотите.

...