2014-10-07 3 views
0

Я читаю книгу C++ Templates: The Complete Guide от Addison Wesley, и у вас есть вопрос об специализациях шаблонов классов. Я понимаю, как это работает, но я не понимаю, когда вы будете использовать эту функцию из данного примера. Вот общее определение класса Stack:Шаблон специализации

#include <vector> 
#include <stdexcept> 

template <typename T> 
class Stack { 
    private: 
    std::vector<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(); 
    } 
}; 

А вот специализация

#include <deque> 
#include <string> 
#include <stdexcept> 
#include "stack1.hpp" 

template<> 
class Stack<std::string> { 
    private: 
    std::deque<std::string> elems; // elements 

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

Моя проблема состоит в том, что он, кажется, нарушить принципы ООП о инкапсуляции. Должен ли клиент знать, что существует два определения, может быть, в разных файлах заголовков, а затем знаете, какой из них следует включать на основе типа T, заданного классу Stack? Мне кажется, что в этом сценарии вам лучше всего реализовать два разных класса: один класс Stack и специализированный класс StackString.

Мысли?

+6

Обычно вы включаете специализацию в тот же заголовок. Пользователю не нужно знать, что они используют специализацию. – juanchopanza

+0

@juanchopanza _ «Пользователю не нужно знать, что они используют специализацию.«_ Я как раз собирался сказать то же самое +, если поведение интерфейса не будет изменено специализацией (которая считается ошибочной, конечно). –

+0

Если вы не можете изменить файл, в котором определен' Stack', создайте еще один файл, скажем «MyStack.h» и добавьте специализацию в этот файл. Убедитесь, что '# include'' MyStack.h' вместо 'Stack.h'. –

ответ

1

нужен ли клиенту, чтобы знать, что есть два определение, может быть, в в различные файлы, а затем знать, какой из них включать на основе типа T дал класс Stack?

Там нет абсолютно никакой необходимости, чтобы поместить их в двух различных открытых заголовков, то есть заголовки, которые пользователь библиотеки будут видеть и использовать. Они могут быть внутренне организованы в два разных заголовка реализации, которые затем включены в основную, которую пользователь увидит и включит. Но пользователь не будет знать, что является явно определенной специализацией, или что он , используя.

// Stack.impl.hpp 

// primary template: 
template <typename T> 
class Stack { 
    // [...] 
}; 

// Stack_StringSpec.impl.hpp 

#include "Stack.impl.hpp" 
// explicit specialization: 
template <> 
class Stack<std::string> { 
    // [...] 
}; 

// Stack.hpp 

#include "Stack.impl.hpp" // Included for clarity 
#include "Stack_StringSpec.impl.hpp" 

Обратите внимание, что в большинстве случаев, специализация по-прежнему будет документировано, как это, безусловно, существует по причине пользователь должен/должна быть в курсе. (Возьмите std::vector<bool> в качестве примера.) Только

+0

Как это будет сделано на практике? Что такое открытый файл заголовка? Это похоже на ответ, который я искал, но я не полностью следую. –

+0

@ Q-bertsuit Отредактирован ответ. – Columbo

0

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

Самая популярная специализация std::vector<bool>. Тип bool принимает 1 байт, но на самом деле один байт может хранить 8 балов. Когда вам нужен массив bools, может показаться разумным упаковать больше их в один байт, чтобы уменьшить потребление памяти. Специализация здесь позволяет достичь именно этого.

Для пользователя все прозрачно: вы используете vector<bool> точно так же, как vector<int>, но в то время как второй полагается на динамический массив из целых чисел, первый играет с битами совершенно по-другому.

Специализация не обязательно должна быть в том же заголовке, но должна быть ваша забота о том, чтобы все специализации были видны, когда пользователь включает класс, иначе он может не использовать их (вы не хотите не забудьте включить другой файл, когда вы используете vector<bool>).

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