Как обобщить контейнерные адаптеры с помощью шаблонов?

У меня есть следующий класс:

#include <set>
#include <stack>
#include <queue>
#include <string>

template <typename T>
class MySet
{
    public:
        const std::stack<T> data() const
        {
            std::stack<T> other_cont ( typename std::stack<T>::container_type ( cont.begin(), cont.end() ) );
            return other_cont;
        }

    private:
        std::set<T> cont;
};

И следующий код:

MySet<std::string> a;
MySet<int> b;

const std::stack<std::string> s = a.data();
const std::queue<int> q = b.data();

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

Вот что я попробовал:

template <template <typename> typename M>
const M<T> data() const
{
    M<T> other_cont ( typename M<T>::container_type ( cont.begin(), cont.end() ) );
    return other_cont;
}

Компилятор говорит, что не может вывести параметр шаблона M,

2 ответа

Решение

Рассмотрим ваш телефонный код:

a.data()

Здесь нет ничего для data() вывести его тип возвращаемого значения. Вы должны уточнить это явно, что-то вроде:

a.data<std::stack>()

Но из ваших комментариев вы не можете редактировать код использования. Что вы можете сделать, это использовать оператор преобразования типа шаблона:

template <typename M>
operator M() const
{
    M other_cont ( typename M::container_type ( cont.begin(), cont.end() ) );
    return other_cont;
}

Чтобы сохранить код неотредактированным, ваш data Метод должен вернуть этот объект:

const MySet<T> data() const
{
    return *this;
}

Простой подход заключается в использовании оператора преобразования:

#include <set>
#include <stack>
#include <queue>
#include <string>

template <typename T>
class MySet
{
    public:
        template <typename O, typename = typename O::container_type>
        operator O() const
        {
            return O(typename O::container_type(cont.begin(), cont.end()));
        }

    private:
        std::set<T> cont;
};

Используя этот подход, обозначения отличаются, хотя: нет data() член используется:

int main()
{
    MySet<std::string> s;
    std::stack<std::string> st = s;
    std::queue<std::string> qu = s;
} 

Если вы хотите использовать data() член и получить различные типы из результата, вам нужно вернуть прокси, который соответствующим образом конвертируется при доступе:

#include <set>
#include <stack>
#include <queue>
#include <string>

template <typename T>
class MySet
{
    public:
        class Proxy {
            std::set<T> const* set;
        public:
            Proxy(std::set<T> const* s): set(s) {}
            template <typename O, typename = typename O::container_type>
            operator O() const
            {
                return O(typename O::container_type(set->begin(), set->end()));
            }
        };

        Proxy data() const { return Proxy{&this->cont}; }
    private:
        std::set<T> cont;
};

int main()
{
    MySet<std::string> s;
    std::stack<std::string> st = s.data();
    std::queue<std::string> qu = s.data();
} 
Другие вопросы по тегам