C ++, передать два пакета параметров в конструктор - PullRequest
0 голосов
/ 25 ноября 2018

У меня следующая проблема.У меня есть класс ( mixin ), который имеет две базы шаблонов.

template <typename T>
class Id
{
    using result = T;
};

template <typename Printer1, typename Printer2>
class SeveralPrinters : public Printer1, public Printer2
{
    template <typename... Args1, typename... Args2>
    SeveralPrinters(dummy, helper<Args1...>, helper<Args2...>,
                    typename Id<Args1>::result... args1,
                    typename Id<Args2>::result... args2)
        : Printer1(std::forward<Args1>(args1)..., std::forward<Args2>(args2)...)
    {}
public:
    template <typename... Args, typename = 
std::enable_if_t<!contains<dummy, Args...>::result>>
    SeveralPrinters(Args&&... args)
        : SeveralPrinters(dummy(), typename Printer1::ArgsCtor(), 
typename Printer2::ArgsCtor(), std::forward<Args>(args)...)
    {
    }
};

Все имена классов являются вымышленными.Итак, представьте, что его первая база принимает int в качестве аргумента конструктора, а вторая база принимает double.Что я хочу сделать, так это уметь вызывать конструктор из SeveralPrinters как SeveralPrinters(1, 2.).Проблема здесь в том, что Args1 и Args2 выводятся не из структуры helper, а из аргументов, передаваемых после вспомогательной структуры.Как видите, я попытался обернуть аргументы шаблона в структуру Id, но это не помогло.Я знаю, что это называется чем-то вроде Невыбранный контекст , но мне не удалось заставить его работать.Может ли кто-нибудь помочь с этим (если это возможно), и, возможно, объяснить немного больше по этой теме (почему это не работает сейчас).Пример базовых классов:

class BasicPrinter1
{
public:
    BasicPrinter1(int)
    {}
    void f()
    {
    }
    using ArgsCtor = helper<int>;
};

class BasicPrinter2
{
public:
    BasicPrinter2(int*)
    {}
    void g()
    {
    }
    using ArgsCtor = helper<int*>;
};

1 Ответ

0 голосов
/ 25 ноября 2018

Он не работает главным образом потому, что псевдоним result в Id имеет значение private (доступность по умолчанию для классов) и поэтому недоступен из частного конструктора SeveralPrinters, что приводит кошибка замещения (typename Id<Args1>::result) без другого жизнеспособного конструктора-кандидата для вызова.В вашем коде также было несколько опечаток.

template <typename T>
struct Id
{
    using result = T;
};

template <typename Printer1, typename Printer2>
class SeveralPrinters : public Printer1, public Printer2
{
    template <typename... Args1, typename... Args2>
    SeveralPrinters(dummy, helper<Args1...>, helper<Args2...>
                  , typename Id<Args1>::result... args1
                  , typename Id<Args2>::result... args2)
        : Printer1(std::forward<Args1>(args1)...)
        , Printer2(std::forward<Args2>(args2)...)
    {}

public:    
    template <typename... Args>
    SeveralPrinters(Args&&... args)
        : SeveralPrinters(dummy{}
                        , typename Printer1::ArgsCtor{}
                        , typename Printer2::ArgsCtor{}
                        , std::forward<Args>(args)...)
    {}
};

DEMO


Для идеальной пересылки аргументовдля базовых классов вы должны вместо этого объявить количество параметров (ArgsCount) и использовать следующую реализацию:

template <typename Printer1, typename Printer2>
class SeveralPrinters : public Printer1, public Printer2
{
    template <std::size_t... Is
            , std::size_t... Js
            , typename... Args>
    SeveralPrinters(std::index_sequence<Is...>
                  , std::index_sequence<Js...>
                  , std::tuple<Args...>&& t)
        : Printer1(std::get<Is>(std::move(t))...)
        , Printer2(std::get<sizeof...(Is) + Js>(std::move(t))...)
    {}

public:
    SeveralPrinters() = default;
    SeveralPrinters(const SeveralPrinters&) = default;
    SeveralPrinters(SeveralPrinters& rhs)
        : SeveralPrinters(static_cast<const SeveralPrinters&>(rhs))
    {}

    template <typename... Args>
    SeveralPrinters(Args&&... args)
        : SeveralPrinters(std::make_index_sequence<Printer1::ArgsCount>{}
                        , std::make_index_sequence<Printer2::ArgsCount>{}
                        , std::forward_as_tuple(std::forward<Args>(args)...))
    {}
};

struct BasicPrinter1
{
    BasicPrinter1(int) {}
    static constexpr ArgsCount = 1;
};

struct BasicPrinter2
{
    BasicPrinter2(int*, char&) {}
    static constexpr ArgsCount = 2;
};

DEMO 2

Также обратите внимание на то, как я защищаю конструктор копирования от того, чтобы он был омрачен конструктором пересылочных ссылок.

...