CodeInside
@CodeInside

Как реализовать частичную специализацию для указателя на определённый класс?

Мне нужно реализовать специализацию двух шаблонных методов для указателя на класс Storage_device. Уже много примеров пересмотрел, но никак не получается это сделать. Вот на чём получается меньше всего ошибок:
объявление метода в классе
template <typename Node, typename DataType>
class List
{
	Node *head, *tail;
	int count;

public:
	// ...
	void AddHead(DataType data);

сама специализация
template <typename Node>
void List<Node, Storage_device*>::AddHead(Storage_device* data)
{
	Node* temp = new Node;
	temp->prev = nullptr;
	temp->*data = *data;
	temp->next = head;
	if (head != nullptr)
		head->prev = temp;
	head = temp;
	if (tail == nullptr)
		tail = temp;
	count++;
}

Ошибки: List::AddHead: не удаётся сопоставить определение функции существующему объявлению.
Текст второй ошибки идентичен. Заранее благодарю за помощь.
  • Вопрос задан
  • 160 просмотров
Решения вопроса 2
Так как вы хотите специализировать параметры шаблона класса, то придётся специализировать весь класс:

template <typename Node, typename DataType>
class List
{
  Node *head, *tail;
  int count;

public:
  // ...
  void AddHead(DataType data);
};

template <typename Node>
class List<Node, Storage_device*>
{
  using DataType = Storage_device*;

  Node *head, *tail;
  int count;

public:
  // ...
  void AddHead(DataType data);
};

Теперь для этой специализации класса получится определить AddHead, как у вас.

Можно обойтись без специализации всего класса, искусственно добавив шаблон в функцию:

template<typename = std::enable_if<std::is_same<DataType, Storage_device*>>::type>
void AddHead(DataType data);  // specialized version

template<typename = std::enable_if<!std::is_same<DataType, Storage_device*>>::type>
void AddHead(DataType data);  // general version

Правда, я давно не использовал std::enable_if, не гарантирую, что это работает.

template<typename Node, typename DataType>
class List {
    //...
public:
    template<typename = std::enable_if<std::is_same<DataType, Storage_device*>>::type>
    void AddHead(DataType data);

    template<typename = std::enable_if<!std::is_same<DataType, Storage_device*>>::type>
    void AddHead(DataType data);
};

template<typename Node, typename DataType>
template<typename = std::enable_if<std::is_same<DataType, Storage_device*>>::type>
void List<Node, DataType>::AddHead(DataType data);

template<typename Node, typename DataType>
template<typename = std::enable_if<!std::is_same<DataType, Storage_device*>>::type>
void List<Node, DataType>::AddHead(DataType data);
Ответ написан
@MarkusD Куратор тега C++
все время мелю чепуху :)
В общем, Антон Жилин все описал правильно, но есть еще один выход.

Чтобы понять преимущество предлагаемого мной подхода, нужно обратиться к коду std::basic_string.
Например, вот эта реализация.
https://android.googlesource.com/platform/ndk/+/bf...

Вторым параметром идут так называемые черты - traits для типа символов в строке. По своей сути функциональность std::string, std::wstring, std::u16string и std::u32string отличается только реализацией именно этого параметра.
Сам шаблон черт для строки описан немногим выше 75й строки.
Вся реализация std::basic_string полностью опирается на список статических функций из заданных в шаблоне черт.

Я предлагаю вынести частную специализацию за пределы твоего шаблона List и определить черты ListTraits, которые уже и специализировать для нужных классов, в частности - для Storage_device.
В черты можно и нужно выделять только важные функции. Это можно сравнить с вынужденной мерой.

template< typename TDataType >
class ListTraits
{
public:
	// ...
	
	template< typename TNodeType >
	inline static void AddHead( TNodeType node, TDataType data );
	
	// ...
};

template<>
class ListTraits<Storage_device*>
{
public:
	// ...
	
	template< typename TNodeType >
	inline static void AddHead( TNodeType node, Storage_device* data );
	
	// ...
};

template< typename TNodeType, typename TDataType >
class List
{
	// Тип используемых черт.
	using Traits = ListTraits<TDataType>;
	
	TNodeType *head, *tail;
	int count;

public:
	// ...
	
	void AddHead(TDataType data);
	
	// ...
};

template< typename TNodeType, typename TDataType >
void List<TNodeType, TDataType>::AddHead( TDataType data )
{
	// ...
	
	Traits::template AddHead( temp, data );
	
	// ...
};
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы