2013-11-20 5 views
0

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

#include <iostream> 
#include <ostream> 
#include <string> 
#include <cstdlib> 
#include <vector> 
#include <memory> 

template <typename T, 
      template <typename ELEM, 
        typename = std::allocator<ELEM> > 
        class CONT = std::deque> 
class Stack { 

public: 
    typedef typename CONT<T>::size_type size_type; 

    private: 
    CONT<T> elems;   // elements 

    public: 
    void push(T const&); // push element 
    void pop();   // pop element 
    T top() const;   // return top element 
    bool empty() const { // return whether the stack is empty 
     return elems.empty(); 
    } 

     size_type size(); 
}; 

template <typename T, template <typename,typename> class CONT> 
void Stack<T,CONT>::push (T const& elem) 
{ 
    elems.push_back(elem); // append copy of passed elem 
} 

template<typename T, template <typename,typename> class CONT> 
void Stack<T,CONT>::pop() 
{ 
    if (elems.empty()) { 
     throw std::out_of_range("Stack<>::pop(): empty stack"); 
    } 
    elems.pop_back();   // remove last element 
} 

template <typename T, template <typename,typename> class CONT> 
T Stack<T,CONT>::top() const 
{ 
    if (elems.empty()) { 
     throw std::out_of_range("Stack<>::top(): empty stack"); 
    } 
    return elems.back();  // return copy of last element 
} 


template<typename T, 
template<typename, typename= std::allocator<T> > class CONT> 
typename Stack<T, CONT>::size_type Stack<T, CONT>::size() 
{ 
    return elems.size(); 
} 

template <typename T, 
      template <typename ELEM, typename = std::allocator<ELEM> > class CONT> 
static inline void Pout(const CONT<T>& container) 

{ 

    typedef typename CONT<T >::size_type size_type; 

    size_type idx = 0; 
    size_type sz = CONT<T>::size(); 

    CONT<T> temp = container; 
    std::cout << '['; 
    while (idx < sz) 
    { 
    std::cout << temp.top(); 
    temp.pop(); 
    idx++; 
    if (idx == sz) break; 
    std::cout << ", "; 
    } 
    std::cout << "]"; 
} 


int main() 
{ 
    try { 
    Stack<int, std::vector > vStack; 
    //... 
    vStack.push(42); 
    vStack.push(7); 

    Pout<Stack<int, std::vector > >(vStack); 
    } 
    catch (std::exception const& ex) { 
    std::cerr << "Exception: " << ex.what() << std::endl; 
    } 
} 

Я получаю ошибку компилятора с помощью г ++ 4.3.4:

stack8test.cpp: In function int main(): 
stack8test.cpp:28: error: no matching function for call to Pout(Stack<int, std::vector>&) 
make: *** [stack8test.o] Error 1 

Я ценю помощь.

Я внесла изменения, чтобы прокомментировать вызов функции Pout> (vStack) и распечатать содержимое vStack до std :: cout. Вот новый код. Он собирает и работает, как ожидалось:

#include <iostream> 
#include <ostream> 
#include <string> 
#include <cstdlib> 
#include <vector> 
#include <memory> 

#include <deque> 
#include <stdexcept> 

template <typename T, 
      template <typename ELEM, 
        typename = std::allocator<ELEM> > 
        class CONT = std::deque> 
class Stack { 

public: 
    typedef typename CONT<T>::size_type size_type; 
    typedef typename CONT<T>::value_type value_type; 

    private: 
    CONT<T> elems;   // elements 

    public: 
    void push(T const&); // push element 
    void pop();   // pop element 
    T top() const;   // return top element 
    bool empty() const { // return whether the stack is empty 
     return elems.empty(); 
    } 

    size_type size(); 
    void Pout(); 
}; 

template <typename T, template <typename,typename> class CONT> 
void Stack<T,CONT>::push (T const& elem) 
{ 
    elems.push_back(elem); // append copy of passed elem 
} 

template<typename T, template <typename,typename> class CONT> 
void Stack<T,CONT>::pop() 
{ 
    if (elems.empty()) { 
     throw std::out_of_range("Stack<>::pop(): empty stack"); 
    } 
    elems.pop_back();   // remove last element 
} 

template <typename T, template <typename,typename> class CONT> 
T Stack<T,CONT>::top() const 
{ 
    if (elems.empty()) { 
     throw std::out_of_range("Stack<>::top(): empty stack"); 
    } 
    return elems.back();  // return copy of last element 
} 


template<typename T, 
template<typename, typename= std::allocator<T> > class CONT> 
typename Stack<T, CONT>::size_type Stack<T, CONT>::size() 
{ 
    return elems.size(); 
} 


template <typename T, 
template<typename, typename = std::allocator<T> > class CONT> 
void Stack<T, CONT>::Pout() 
{ 

    size_type idx = 0; 
    size_type sz = size(); 

    CONT<T> temp(elems); // make a temp copy of the underlying container and print the temp, since printing is destructive. Note that the underlying CONT must already support copy constructor. 

    std::cout << std::endl << '['; 
    while (idx < sz) 
    { 
    std::cout << temp.back(); 
    temp.pop_back(); 
    idx++; 
    if (idx == sz) break; 
    std::cout << ", "; 
    } 
    std::cout << "]" << std::endl;; 

} 
template <typename T, 
      template <typename ELEM, typename = std::allocator<ELEM> > class CONT> 
void Pout(const CONT<T>& container) 

{ 

    typedef typename CONT<T >::size_type size_type; 

    size_type idx = 0; 
    size_type sz = CONT<T>::size(); 

    CONT<T> temp = container; 
    std::cout << '['; 
    while (idx < sz) 
    { 
    std::cout << temp.top(); 
    temp.pop(); 
    idx++; 
    if (idx == sz) break; 
    std::cout << ", "; 
    } 
    std::cout << "]"; 
} 


int main() 
{ 
    try { 
    Stack<int, std::vector > vStack; 
    //... 
    vStack.push(42); 
    vStack.push(7); 

// Pout<Stack<int, std::vector > >(vStack); 
    vStack.Pout(); 
    std::cout << "vStack = [" << vStack.top(); vStack.pop(); 
    std::cout << ", " << vStack.top() << "]" << std::endl; vStack.pop(); 
    } 
    catch (std::exception const& ex) { 
    std::cerr << "Exception: " << ex.what() << std::endl; 
    } 
} 

Выход Компилятор:

g++ -O2 -g -Wall -c -o stack8test stack8test.cpp 

Запуск программы, я получил:

./stack8test 
vStack = [7, 42] 

Моя реальная проблема найти правильный синтаксис для шаблон функции Pout, чтобы распечатать содержимое моего шаблона шаблона Stack. Чтобы уточнить, я намерен реализовать шаблон класса Stack как контейнер элементов типа T. Я хочу реализовать Stack в терминах контейнера std типа std :: vector или std :: deque или даже std :: list ,

Я назвал Pout как:

Pout<int, Stack<int, std::vector>>(vStack); 

Но компилятор до сих пор говорит:

stack8test.cpp: In function int main(): 
stack8test.cpp:137: error: no matching function for call to Pout(Stack<int, std::vector>&) 
make: *** [stack8test.o] Error 1 

UPDATE: В работе вокруг моей первоначальной исходной задачи глобальной (то есть, не являющихся членами) для печати содержимого моего Stack в std :: cout, я определил Pout() как функцию-член. Он компилируется и работает так, как ожидалось. Поиск правильного синтаксиса для глобальной функции остается проблемой.

+0

Когда вы используете 'std :: deque', вы должны (также) включать заголовок' '. – dyp

+0

Извините, что не комментировал ранее. Я был болен. – user2975538

+0

Извините, что не комментировал ранее. Я был болен. Я не уверен, что вы понимаете мой дизайн: Stack - это контейнер шаблонов классов, который может быть реализован либо с помощью одного из контейнеров STL: vector или deque. Я думаю, что это разумный дизайн. @Mikhail – user2975538

ответ

2

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

template <typename T, 
     template <typename ELEM, typename = std::allocator<ELEM> > class CONT> 
static inline void Pout(const CONT<T>& container) 

просто написать

template <class CONT> 
static inline void Pout(const CONT& container) 

Это, как это делается в STL. Если вам необходимо получить доступ к основному типу контейнера, опять же, использовать STL подход и добавить value_type ЬурейиЕ к классу:

class Stack { 
public: 
    ... 
    typedef T value_type; 
    ... 
} 

Вы можете получить доступ к нему в качестве функции CONT::value_type. Однако вы даже не используете эту информацию в функции Pout.

Некоторые другие ошибки:

  • Марк size функционируют как const, как это должно быть
  • Не используйте static inline спецификаторов для вас functionы если вы не 100% уверен, что вы знаете, что вы делаете. Наверное, нет.

Код компилируется после исправления этих ошибок, но общая конструкция довольно плохая.

+0

My Stack предназначен для шаблона класса, который реализован в терминах вектора STL или контейнера deque. Параметрами являются как тип элемента стека T, так и тип STL контейнера. Таким образом, параметр CONT должен быть параметром шаблона шаблона. Pout предназначен как функция шаблона, которая печатает элементы my Stack > в std :: cout. Что-то не так с этой концепцией? – user2975538

+0

Это зависит от задач, которые вы хотите решить с помощью этой концепции. Первое правило о программировании шаблонов на C++ заключается в том, чтобы избежать его сложности, если вы действительно не уверены, что вам это нужно. – Mikhail

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