2016-12-19 4 views
2

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

#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.

+1

Я не думаю, что компилятор может когда-либо выводим параметр в вашем случае. Попробуйте const 'std :: queue q = b.data ();' или даже 'std :: queue q = b.data >();' –

+0

Извините, я не упоминал об этом является частью какого-либо материала из экзаменов прошлых лет, и я не могу коснуться второго блока кода. – Jani

+0

Я только предположил, что я должен решить это с помощью шаблонов, поскольку код для обоих адаптеров идентичен. – Jani

ответ

3

Рассмотрим код вызова:

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; 
} 
3

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

#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(); 
} 
+0

Есть ли преимущество в том, чтобы обернуть его в класс Proxy вместо определения оператора преобразования прямо в MySet? (Как в ответе @ wasthishelpful-s) – Jani

+0

Тот же вопрос для 'typename = typename O :: container_type', я что-то теряю, если просто использую' template ' – Jani

+1

@Jani: по существу сообщения об ошибках разные. Используя мой подход SFINAE скажу, что нет соответствующего оператора преобразования, если тип назначения не имеет вложенного 'container_type'. Без этого будет ошибка, связанная с неправильной реализацией. В контексте SFINAE моя реализация не будет требовать, чтобы она была конвертируемой. Независимо от того, используете ли вы прокси-сервер или нет, зависит от того, хотите ли вы упомянуть 'data()' или нет. –

Смежные вопросы