Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Частичная специализация методов в шаблоне класса
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > Программирование
jorikdima
Здравствуйте.
Никогда не любил шаблоны, видимо потому что спал, когда на лекциях про них рассказывали, либо синтаксис просто жутко сложен. В общем сейчас нужна подсказка по ним. Использую scmRTOS, там шаблоы используются часто, в том чиле и для реализации кольцевого буфера.
Код
template<typename T, word Size, typename S = byte>
    class ring_buffer
    {
    public:
        ring_buffer() : Count(0), First(0), Last(0) { }

        //----------------------------------------------------------------
        //
        //    Data transfer functions
        //
        bool write(const T* data, const S cnt);
        void read(T* const data, const S cnt);
............................................................

У шаблона 3 параметра: тип хранимых данных, размер буфера и тип индексов. Есть функции записи и чтения, которые тоже реализованы шаблоном:
Код
template<typename T, word Size, typename S>
void usr::ring_buffer<T, Size, S>::read(T* data, const S cnt)
{
}

Так вот, я могу специализировать этот метод для конкретных параметров шаблона, например:
Код
template<>
void usr::ring_buffer<int, 100, int>::read(int* data, const int cnt)
{
}

И так оно работает (по крайней мере компилируется). Но! В данном случае, такой параметр шаблона как размер буфера, я бы хотел так и оставить параметом, специализировать я хочу только тип данных и тип индексов.
Хотел бы написать что-то вроде:
Код
template<>
void usr::ring_buffer<int, Size, int>::read(int* data, const int cnt)
{
}

Но говорит, что не знает что такое Size.
Я видел про специализацию шаблонов классов, но на сколько я понял, это более глобально, чем нужно мне. Не придется ли мне там переопределять все методы и поля класса? Мне-то нужно только read и write определить для частного случая хранения int. Как это описать?
Спасибо.
sergeeff
Параметры шаблона должны быть определены на момент компиляции, посему параметры шаблона: типы, целые числа и enum.
shreck
Погуглите "Симуляция частичной специализации". Будет много информации. Но при отсутствии поддержки компилятора, реализация частичной специализации будет не такой изящной, как вам хотелось бы.
dxp
Цитата(jorikdima @ Jun 23 2010, 02:15) *
Так вот, я могу специализировать этот метод для конкретных параметров шаблона, например:
Код
template<>
void usr::ring_buffer<int, 100, int>::read(int* data, const int cnt)
{
}

И так оно работает (по крайней мере компилируется).

Это полная специализация шаблона. Т.е. по сути это просто отдельная полная реализация класса со всеми вытекающими - рост размера программы.

Цитата(jorikdima @ Jun 23 2010, 02:15) *
Но! В данном случае, такой параметр шаблона как размер буфера, я бы хотел так и оставить параметом, специализировать я хочу только тип данных и тип индексов.
Хотел бы написать что-то вроде:
Код
template<>
void usr::ring_buffer<int, Size, int>::read(int* data, const int cnt)
{
}

Но говорит, что не знает что такое Size.

Тут синтаксическая ошибка. Частичная специализация задается как обычное определение шаблона за исключением того, что в аргументах указываются конкретные типы:
Код
template<typename T, word Size, typename S>
void usr::ring_buffer<int, Size, int>::read(T* data, const S cnt)
{
}

В этом случае для типа, создаваемого из шаблона с параметрами <int, unsigned short, int> будет использоваться эта специализированная функция.

Вообще, частичная специализация просится в этот шаблон для работы с указателями. Это классический пример. Но все руки никак не дойдут написать это и выложить. smile.gif
jorikdima
Спасибо за ответы.
DXP,
я пробовал тот синтаксис, что Вы привели, но к сожалению либо что-то недопонимаю, либо просто ошибка. Для примера я создал в VisualStudio проект, чтоб абстрагироваться от остального кода. Собственно там всего два файла:
.h
Код
template<typename T, int Size, typename S = char>
class ring_buffer
    {
    public:
        ring_buffer(): Count(0), First(0), Last(0) { }

        bool write(const T* data, const S cnt);
        void read(T* const data, const S cnt);
    private:
        S  Count;
        S  First;
        S  Last;
        T  Buf[Size];
    };

.c
Код
#include "t1.h"

template<typename T, int Size, typename S>
bool ring_buffer<T, Size, S>::write(const T* data, const S cnt)
    {
    return true;
    }

template<typename T, int Size, typename S>
void ring_buffer<T, Size, S>::read(T* data, const S cnt)
    {
    }

template<typename T, int Size, typename S>
void ring_buffer<char, Size, char>::read(T* data, const S cnt)
    {
    }

ring_buffer<char, 10> tmp;
void main()
    {

    tmp.write("ddsdsd", 7);

    }

Студия говорит:
Цитата
d:\mydocs\visual studio 2008\projects\templ\t1.cpp(17) : error C3860: template argument list following class template name must list parameters in the order used in template parameter list
1>d:\mydocs\visual studio 2008\projects\templ\t1.cpp(17) : error C2995: 'void ring_buffer<T,Size,S>::read(T *const ,const S)' : function template has already been defined
1> d:\mydocs\visual studio 2008\projects\templ\t1.h(10) : see declaration of 'ring_buffer<T,Size,S>::read'


Судя по всему, нельзя сделать так как я хочу. А именно, для конкретного набора параметров переопределить только два метода write и read , а реализацию остальных методов возложить на компилятор на общих основаниях. Тут либо не рыпаться, либо переписывать ВСЕ методы класса (вплоть до копипаста) для конкретного набора параметров. Странно, почему так...
dxp
Цитата(jorikdima @ Jun 23 2010, 14:06) *
Судя по всему, нельзя сделать так как я хочу. А именно, для конкретного набора параметров переопределить только два метода write и read , а реализацию остальных методов возложить на компилятор на общих основаниях. Тут либо не рыпаться, либо переписывать ВСЕ методы класса (вплоть до копипаста) для конкретного набора параметров. Странно, почему так...

Да, тут с вашей хотелкой засада. Вам по сути нужна полная специализация функции-члена, но такая специализация допускается только для шаблонов с одним параметром (а там три).

Второй вариант - частичная специализация шаблона класса:
Код
template<word Size>
class ring_buffer<int, Size, int>
{
public:
    ...
    bool write(const int* data, const int cnt);
    void read(int* const data, const int cnt);
    ...
};

Но тут придется все члены определять.

Почему так? Трудный (для меня) вопрос. Наверное, потому, что специализация - это всегда другая реализация, поэтому она должна быть информационно самостоятельной. Цель специализации - предоставить статический полиморфизм: использующий код один и тот же, а реализации подставляются разные.
jorikdima
Спасибо большое за ответы, dxp. Буду идти каким-нибудь другим путем.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.