C ++ список неспециализированных объектов типа шаблона? - PullRequest
0 голосов
/ 13 ноября 2018

Я искал вопросы на эту тему, и, хотя есть похожие, никто не ответил на мой вопрос. Итак, я иду.

Предположим, у меня есть шаблон типа F, и я объявляю серию специализаций как переменные-члены другого объекта:

F<A> a;
F<B> b;
.
.
.

Позже я бы хотел выполнить итерации по ним и выполнить операцию, определенную для любого экземпляра F.

Так что мой импульс - создать std :: list , но это не работает.

Есть ли способ создать список объектов типа F, то есть без указания параметра шаблона?

Моя догадка - нет, не в C ++, но надеюсь, что я ошибаюсь.

Ответы [ 3 ]

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

Что касается C ++, два разных экземпляра шаблона класса или структуры шаблона являются совершенно отдельными типами и не имеют никакого отношения друг к другу. Например, std::vector<int> и std::vector<char> являются отдельными типами; не происходит ни от другого, ни от какой-либо общей базы. Тот факт, что оба типа возникли из экземпляров одного и того же шаблона, не создает семантических отношений между типами. В этом смысле (и в этом смысле только ) вы можете подумать о шаблонах, подобных макросам препроцессора, которые перед компиляцией раскрываются для объявления новых и не связанных типов.

Но вы можете сами создать такие отношения, используя наследование, так же, как и с любыми не шаблонными типами:

#include <iostream>

struct foo_base {
    virtual void print() = 0;
};

template <typename T>
struct foo : foo_base {
    foo(T data) : data(data) {}
    virtual void print() override {
        std::cout << data << std::endl;
    }
    private: T data;
};

void example() {
    foo<int> f(42);
    f.print();
}

Здесь foo<int> и foo<char> являются отдельными типами (как отдельные экземпляры шаблона foo<>), но все экземпляры foo<> происходят от foo_base. (Если, конечно, вы не предоставите явную специализацию foo<>, которая не является производной от foo_base ...)

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

Если все F<X> не получены из некоторого общего базового класса, независимого от X, это возможно только при использовании стирания типов или гетерогенных контейнеров.

Если все они наследуются от Foo, то изКонечно, вы можете перебирать их как Foo& / Foo*, но я думаю, вы знали, что.

Если они имеют разные типы, стандартные контейнеры не могут их содержать, потому что они однородны - все элементы имеюттого же типа.Вероятно, есть какая-то библиотека с гетерогенными контейнерами, но в STL вы можете эмулировать это только с помощью std::variant или std::any.

Последний способ, которым я мог представить, работает - я не рекомендую это- путем создания включающего класса как производного класса F<X> s (шаблон переменной) и кодирования вызовов в иерархии, каждый F s foo` называется

, поскольку это несколько большеЗдесь приведен пример:

#include <iostream>

template <class X>
class Foo {
    X mem;
    public:
    explicit Foo(X arg) : mem(arg) {}
    void foo() {
        std::cout << mem;
    }
};

template <class X, class ...Xs> class Holder;

template <class X>
class Holder<X> {
    X member;
    public:
    Holder(X arg) : member(std::forward<decltype(arg)>(arg)) {}
    void call() {
        member.foo();
    }
};

template <class X, class ...Ys>
class Holder : public Holder<Ys...> {
    X member;
    public:
    Holder(X arg, Ys ...args) : Holder<Ys...>(std::forward<decltype(args)>(args)...), member(std::forward<decltype(arg)>(arg)) { }

    void call() {
        member.foo();
        Holder<Ys...>::call();
    }
};

int main() {
   // omitting the template-args requires c++17 deduction guides
    Holder holder(Foo(4), Foo(" Hello "), Foo(7L), Foo(" World "));
    holder.call();
    std::cout << std::endl;
}

Возможно, вы сможете догадаться, что это, как правило, не то, что вам нужно, потому что это очень сложно.На самом деле я пропустил некоторые вещи, такие как идеальная пересылка аргументов, чтобы сделать их несколько минимальными, и можно надеяться, что концепция понятна.

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

К сожалению, ответ НЕТ . В C ++ вы не можете иметь контейнер разнородных неродственных объектов, и разные экземпляры одного и того же шаблона не связаны.

Единственный способ заставить его работать, это использовать некоторую форму стирания типа. Наиболее идиоматичным является использование наследования и виртуальных функций, а также указатели на базовый объект в вашем списке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...