LINUX.ORG.RU

Шаблоны c++: Чaстичная спецификация конструктора.

 , , , ,


0

3

Всем привет.

Есть шаблон такого рода:

template<class TValue, typename TIndex>
class CSet{
public:
  CSet();
};

template<class TValue, typename TIndex>
CSet<TValue,TIndex>::CSet()
{
  ...
};

А теперь нужно сделать отдельный конструктор для TIndex=char, притом TValue остается шаблонным. Нерабочий пример:

template<class TValue>
CSet<TValue,char>::CSet()
{
  ...
};
Если специфицировать оба типа - все работает. А нужно только один. Как?

P. S. Зная, что зачастую проблема в подходе, скажу зачем мне это нужно. В классе есть операции, для которых важно не выйти за пределы значения. Соотв. нужно определять максимальные значения индекса, которые, в свою очередь зависит от типа индекса. Если можно как-то еще это сделать, с готовностью выслушаю.

★★★★★

Конструктор вызывается для уже вполне определенного (инстанциированного) класса. Т.е. конструктор-то у тебя не шаблонный. Шаблонный только класс. Потому не пытайся переделать конструктор.

Pavval ★★★★★ ()

нужно сделать отдельный конструктор

нужно сделать отдельный темплейтный класс, частично специфицировав исходный темплейт. отдельно с методом ничего не сделаешь.

template <class TValue>
class CSet <TValue, char> {}
x0r ★★★★★ ()
Ответ на: комментарий от Pavval

Потому не пытайся переделать конструктор.

Я не переделываю. Я делаю. Мне просто нужна отдельная имплементация для случая когда индекс - char.

Kroz ★★★★★ ()
Ответ на: комментарий от x0r

ужно сделать отдельный темплейтный класс, частично специфицировав исходный темплейт. отдельно с методом ничего не сделаешь.

Вот этого я и боялся :(

Kroz ★★★★★ ()

Соотв. нужно определять максимальные значения индекса, которые, в свою очередь зависит от типа индекса.

traits, в виде отдельного класса.

Pavval ★★★★★ ()
Ответ на: комментарий от Kroz

Дополнительный базовый класс, например?

template< class TIndex > class CSetBase { ... };
... // Специализация CSetBase для разных типов индексов...
template< class TValue, class TIndex > class CSet : public CSetBase< TIndex > { ... }; 

Либо нужно знать, что именно внутри CSet будет зависеть от TIndex. Например, часть каких-то полей, которые можно объединить в структуру:

template< class TIndex > struct CSetInternals
{
};
// Специализация для char.
template<> struct CSetInternals< char >
{
  static const char MaxIndex = { ... };
  static const char MinIndex = { ... };
  ... /* Еще что-то сильно завязанное на специфику char */
};
После чего внутри CSet:
template< class TValue, class TIndex > class CSet
{
  CSetInternals< TIndex > Internals;
... // Все остальное.
};

eao197 ★★★★★ ()
Ответ на: комментарий от eao197

Можно проще: не статические переменные, а статические функции:

template<typename T>
class CTypeInfo{
public:
  static T GetMax();
  static T GetMin();
};
И далее забрать значение как CTypeInfo<char>::GetMax();. Тогда не нужно будет создавать переменные/объекты.

Но всплыла другая проблема. Дело в том, что, если сделать typedef char TCustomType;, то CTypeInfo<TCustomType>::GetMax(); вызовет CTypeInfo<char>::GetMax();, а это абсолютно не то, что мне нужно. Мне нужен индекс с допустимыми значениями, например, 0..75, и валидировать преобразования из всяких int, size_t и т. п. Чувствую, придется городить вообще отдельный класс для индекса :(.

Kroz ★★★★★ ()

В классе есть операции, для которых важно не выйти за пределы значения. Соотв. нужно определять максимальные значения индекса, которые, в свою очередь зависит от типа индекса.

Привязаться к std::numeric_limits ?

Uter ()
Ответ на: комментарий от Kroz

И далее забрать значение как CTypeInfo<char>::GetMax();. Тогда не нужно будет создавать переменные/объекты.

Это не обязательно. Я привел пример структуры и экземпляра CSet::Internals т.к. ничего не известно о том, что именно вам нужно. Если нужны статические данные, то проще без функций:

template< class TIndex > struct CInternals { };
template<> struct CIntervale<char> {
  static const char MaxIndex = 17;
  static const char MinIndex = 8;
};

// Использование.
if( index < CInternals<TIndex>::MaxIndex ) ...

Мне нужен индекс с допустимыми значениями, например, 0..75, и валидировать преобразования из всяких int, size_t и т. п. Чувствую, придется городить вообще отдельный класс для индекса :(.

Ну вы бы точнее исходную задачу сформулировали. А то начинаете с того, что пить хочется, а оказывается, что переночевать негде :)

eao197 ★★★★★ ()
Ответ на: комментарий от Uter

Привязаться к std::numeric_limits ?

Кстати, да, про это я забыл. Спасибо за наводку.

Kroz ★★★★★ ()

Оно?

template<class TValue, typename TIndex>
class CSet {
public:
	CSet() {
		if(std::is_same<TIndex, char>::value) {
			/* char */
		}
		else {
			/* other */
		}
	}
};
Kuzy ★★★ ()
Ответ на: комментарий от Kuzy

Оно?

О, да, оно. Отвечает на вопрос в топике. Спасибо!

Kroz ★★★★★ ()
Ответ на: комментарий от Kuzy

Когда такие ифы делают, обе ветки должны корректно компилироваться при любом значнии TIndex, на практике такое нечасто получается

redbaron ★★ ()
Ответ на: комментарий от redbaron

Поэтому придумали SFINAE;-)

ЧИтать Вандевурд Д. Шаблоны C++ Справочник разработчика. до просветления.

AIv ★★★★★ ()
Ответ на: комментарий от redbaron
#include <iostream>
#include <type_traits>

struct Foo {};

template<class TValue, typename TIndex>
class CSet {
public:
	CSet() {
		TIndex* t;
		construct(t);
	}
	
	void construct(Foo*) {
		std::cout << "Foo" << std::endl;
	}
	
	void construct(...) {
		std::cout << "other" << std::endl;
	}
};

int main() {
	CSet<int, char> a;
	CSet<int, Foo> b;
	

	return 0;
}
Kuzy ★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.