Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Специализация конструктора с параметром callback


Автор: null56 1.2.2010, 15:25
Всем привет
Поясню что хочу сделать: хочу создать такой класс - шаблон, который бы принимал два параметра:
- тип хранимого значения
- функция callback, которую бы он вызывал у себя в деструкторе, другими словами автоматический закрыватель каких - либо хендлов
Пытаюсь определить полную специализацию конструктора класса для типа int, но видимо не правильно определяю ее
Класс
Код

template <typename T, void (*f)(T)>
class Class
{
public:
        //-
        Class<int, void (*f)(int)>() { m_Var = 10; } // проблема тут
        //-
        ~Class() { (*f)(m_Var); }
        T m_Var;
};


Вывод компилятора в отношении строки - проблемы

Цитата

1.h:5: ошибка: `*' не может присутствовать в константном выражении
1.h:5: ошибка: a call to a constructor не может присутствовать в константном выражении
1.h:5: ошибка: a function call не может присутствовать в константном выражении
1.h:5: ошибка: некорректный аргумент шаблона 


Вопрос: если моя цель ясна, то подскажите пожалуйста, можно ли специализировать  конструктор класса (методы отдельно точно можно)? если это возможно, то подскажите где я накосячил с синтаксисом?

Заранее благодарен всем откликнувшимся

Автор: 586 1.2.2010, 16:25
Код
// шаблонный класс
template <typename T, void(*f)(T)>
class Class
{
    T m_var;
public:
    Class() { m_var = 10; }
    ~Class() { f(m_var); }
};

// частичная специализация
template <void (*f)(int)>
class Class<int, f>
{
    int m_var;
public:
    Class() { m_var = 10; }
    ~Class() { f(m_var); }
};


// полная специализация

void test(int)
{
}

template <>
class Class<int, test>
{
    int m_var;
public:
    Class() { m_var = 10; }
    ~Class() { test(m_var); }
};

int main()
{
}

Автор: tolgamrab 1.2.2010, 17:08
Рассматриваемая задача не нова. Это классически пример паттерна контейнер(ресурс)
Вариант первый - решение задачи в лоб:
Код

template <class TStore>
class TContainer
{
public:
    typedef void (*TCallback)(TStore&);
private:
    TStore _data;
    TCallback _callback;
public:
    TContainer(TStore &data, TCallback callbackFunction) :
        _data(data), _callback(callbackFunction)
    {}
    ~TContainer(void)
    {
        (*_callback)(data);
    }
};


Использование:
Код

void myReleaser(int& handle);
void someFunction(void)
{
    TContainer<int> container(handle, myReleaser);
}


Но лучше все же не баловаться callback процедурами и писать контейнер исходя из того, что он сам заботится  об удалении ресурса, при необходимости специализировать шаблон для своего типа ресурса хитрым деструктором. А еще лучше - воспользоваться написанным. auto_ptr подходит как нельзя лучше для решения этой задачи. Нужно или написать обертку для хэндла - в конструкторе создаем, в деструкторе удаляем и все это дело на вход auto_ptr, или посмотреть на реализации умных указателей из любой приличной библиотеки. Там можно явно задавать и тип хранимого значения и стратегию удаления.

Автор: null56 1.2.2010, 17:13
586, спасибо, теперь понятнее...
только не могу понять одну фразу из книги про шаблоны
Цитата

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

что имел в виду автор в контексте второго предложения про отдельную функцию - член?

Добавлено через 2 минуты и 30 секунд
tolgamrab, да, про библиотеку согласен, просто разбираюсь с шаблонами... тебе тоже спасибо за пример

Автор: 586 1.2.2010, 18:57
Цитата(null56 @  1.2.2010,  17:13 Найти цитируемый пост)
Цитата
Хотя можно специализивать и отдельную функцию-член, после этого нельзя будет специализировать целый класс

Да. Действительно.
Код
#include <iostream>

template <typename T>
class A
{
public:
    void test();
};

// реализация метода шаблонного класса
template <typename T>
void A<T>::test(void)
{
    std::cout << "A<T>::test()\n";
}

// специализация метода шаблонного класса для int
template <>
void A<int>::test(void)
{
    std::cout << "A<int>::test()\n";
}

// здесь получится объявить полную специализацию шаблонного класса, т.к. нету отдельной специализации методов для типа short
template <>
class A<short>
{
};

// здесь не получается сделать полную специализацию шаблонного класса, т.к. у класса специализированы методы отдельно
/*
template <>
class A<int>
{
};*/

int main()
{
    A<int> a;
    A<char> b;
    a.test();
    b.test();
}

Автор: null56 1.2.2010, 21:12
спасибо, так намного понятнее

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)