Здравствуйте, <Аноним>, Вы писали:
А>Есть шаблонный класс с двумя параметрами. Нужно специализировать его типами из первого и второго списка, сочетая их друг с другом. А>Буст приветствуется, если его код просто свести к небустовскому.
Здравствуйте, Аноним, Вы писали:
А>Привет!
А>Есть шаблонный класс с двумя параметрами. Нужно специализировать его типами из первого и второго списка, сочетая их друг с другом.
А>(1) LPSTR, const LPSTR, LPCSTR, const LPCSTR А>(2) LPWSTR, const LPWSTR, LPCWSTR, const LPWCSTR
А>Должно получится что-то вроде А>
Здравствуйте, Аноним, Вы писали:
А>Привет!
А>Есть шаблонный класс с двумя параметрами. Нужно специализировать его типами из первого и второго списка, сочетая их друг с другом.
А>(1) LPSTR, const LPSTR, LPCSTR, const LPCSTR А>(2) LPWSTR, const LPWSTR, LPCWSTR, const LPWCSTR
А>Должно получится что-то вроде А>
А>Нельзя ли эти 16 специализаций как-то записать короче? Каждая специализация просто наследуется от общего базового класса.
А>Буст приветствуется, если его код просто свести к небустовскому.
Например так
template<> class convertor<LPSTR, LPWSTR> : public convertor_base{};
template<> class convertor<LPSTR, const LPWSTR> : public convertor_base{};
/* ... etc ... */
Насамом деле можно, но для данного конкретного примера короче будет не намного, но для понимания сложнее. см. type traits
Re[2]: Специализация множеством типов
От:
Аноним
Дата:
18.09.07 13:33
Оценка:
Здравствуйте, jazzer, Вы писали:
J>А в чем тогда смысл таких специализаций, если не секрет? В том, что все остальные от этого класса не наследуются?
Да, у остальных типов своя специализация.
J>В твоем случае это будет (не проверял, пишу наобум, но должно работать):
[]
Спасибо, работает.
Не получилось только выделить бустовский код. Возможно, пришло время стратегических решений в пользу использования буста
Здравствуйте, s_viy, Вы писали:
_>Насамом деле можно, но для данного конкретного примера короче будет не намного, но для понимания сложнее. см. type traits
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, s_viy, Вы писали:
_>>Насамом деле можно, но для данного конкретного примера короче будет не намного, но для понимания сложнее. см. type traits
К>Собственно, вот. К>
Без препроцессора было бы вообще здорово решить проблемку. Только вот Ваш способ немного не то делает, что хотелось бы (или я чего-то не понял).
У класса convertor есть фиксированное объявление, в котором нету наследования, так как в большинстве случаев оно не нужно (для типов, отличных от строковых). И специализация convertor строковыми типами происходит совсем в другом месте (файле).
Вот если бы можно было специализацию convertor такую же красивую на шаблонах сделать?
ТОлько вот надо ли это?
ИМХО просто перечислить все пары, а ещё лучше как-то уйти от комбинаторики просто было бы правильнее.
Может задачу детализируешь нменого?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: Специализация множеством типов
От:
Аноним
Дата:
19.09.07 09:53
Оценка:
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Аноним, Вы писали:
А>>Вот если бы можно было специализацию convertor такую же красивую на шаблонах сделать?
E>Ну что тут не сделать? E>
Я не совсем понял, чем эта реализация принципиально отличается от предложенной Кодт?
А на то предложение я ответил, что мне нужна специализация шаблона, в котором нету наследования.
E>ТОлько вот надо ли это? E>ИМХО просто перечислить все пары, а ещё лучше как-то уйти от комбинаторики просто было бы правильнее.
Не уверен. Во-первых, нужно написать уже 64 специализации, а потом их поддерживать, во-вторых хотелось бы ещё, кроме строковых указателей, заспециализировать строковые массивы, что без шаблонов вообще не получится сделать (то есть перечисляя все пары).
E>Может задачу детализируешь нменого?
С удовольствием. Нужен универсальный конвертор, который будет использоваться в каких-то базовых сервисах. Чтобы воспользоваться сервисом, человек сначала специализирует конвертор для своих типов, а затем сервис его использует. Для базовых типов конвертор специализируется в одном из общих хидеров. Вопрос как раз в том, как специализировать конвертор для всевозможных строковых типов, в том числе и массивов.
Шаблон примерно такой
template<class TDst, class TSrc>
class fc_convertor
{
public:
static TDst convert(const TSrc& );
};
Примеры использования
const LPCSTR sz = "some";
LPWSTR wsz = convertor<LPWSTR, const LPCSTR>::convert(sz);
LPWSTR wsz = new WCHAR[32];
LPCSTR sz = convertor<LPCSTR, LPWSTR>::convert(wsz);
const CHAR sz[] = "some";
LPCWSTR wsz = convertor<LPCWSTR, const CHAR(&)[5]>::convert(sz); // тут тип через функцию convert выводится
/* и т.д. */
Здравствуйте, Аноним, Вы писали:
А>>>Вот если бы можно было специализацию convertor такую же красивую на шаблонах сделать?
E>>Ну что тут не сделать? E>>
А>Я не совсем понял, чем эта реализация принципиально отличается от предложенной Кодт?
Наверное не чем. Я просто из головы написал да и всё. А>А на то предложение я ответил, что мне нужна специализация шаблона, в котором нету наследования.
А зачем тебе она нужна?
Что мешает предоставить пользователю специализировать convertor<T1, T2> для своих типов, а тебе, для своих, оставить реализацию по умолчанию, которая сводится к наследованию из правильно выбранной базы + определение в выведенном конверторе нужных конструкторов (я так понял, что тебе никакие не нужны)
А>кроме строковых указателей, заспециализировать строковые массивы, что без шаблонов вообще не получится сделать (то есть перечисляя все пары).
Да ладно, какие-то из пар можно сделать шаблонными...
Ну если таки надо, то можно так вот через триатс извратиться, вполне реальный план.
Только сложный код получится какой-то, хотя если у тебя всё равно библиотека шаблонная насквозь, то, ИМХО, она всё равно извратная выйдет, так что какая разница
Ты, кстати, почему тогда буст не хочешь привернуть? Если уж на такие извраты идёшь?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[7]: Специализация множеством типов
От:
Аноним
Дата:
19.09.07 14:09
Оценка:
Здравствуйте, Erop, Вы писали:
[]
А>>А на то предложение я ответил, что мне нужна специализация шаблона, в котором нету наследования. E>А зачем тебе она нужна?
Мне нужно специализировать convrtor<> для базовых строковых типов. Наследование — частный случай полной специализации шаблона convertor строковыми типами. Базовый шаблон не наследуется и не должен от чего-либо наследоваться.
E>Что мешает предоставить пользователю специализировать convertor<T1, T2> для своих типов, а тебе, для своих, оставить реализацию по умолчанию, которая сводится к наследованию из правильно выбранной базы + определение в выведенном конверторе нужных конструкторов (я так понял, что тебе никакие не нужны)
Ну можно, на крайняк, завести пустую фэйковую базу для дефолтной реализации... но как-то это некузяво и излишне.
А>>кроме строковых указателей, заспециализировать строковые массивы, что без шаблонов вообще не получится сделать (то есть перечисляя все пары). E>Да ладно, какие-то из пар можно сделать шаблонными...
Не какие-то из пар, а + ещё кучу шаблонных пар
E>Ну если таки надо, то можно так вот через триатс извратиться, вполне реальный план.
Как так вот, я так и не понял
E>Только сложный код получится какой-то, хотя если у тебя всё равно библиотека шаблонная насквозь, то, ИМХО, она всё равно извратная выйдет, так что какая разница
Библиотека уже умными людьми давно писана. И вышло без извратов, по крайней мере, в местах где используются шаблоны
E>Ты, кстати, почему тогда буст не хочешь привернуть? Если уж на такие извраты идёшь?
Вообще, это вопрос времени. Пока банально некогда, а главное — не особо нужно было.
А что касается конкретно этого случая и предложенного к нему решения jazzer на макросах, то тут буст себя не с самой лучшей стороны показал. ИМХО. Хотя, каждому своё. Я, например, не макросоман, скорее макрософоб
Здравствуйте, <Аноним>, Вы писали:
А>>>А на то предложение я ответил, что мне нужна специализация шаблона, в котором нету наследования. E>>А зачем тебе она нужна? А>Мне нужно специализировать convrtor<> для базовых строковых типов. Наследование — частный случай полной специализации шаблона convertor строковыми типами. Базовый шаблон не наследуется и не должен от чего-либо наследоваться.
Ещё раз спрашиваем: ЗАЧЕМ базовый шаблон должен не наследоваться.
Это какие-то религиозные предубеждения, или какие-то тонкие игры с layout'ом объекта, или что?
Здравствуйте, Аноним, Вы писали:
E>>Ну если таки надо, то можно так вот через триатс извратиться, вполне реальный план. А>Как так вот, я так и не понял
Смотри, реализуешь шаблон
template<typename TLeft, typename TRight> class convertor_default_implementation {
// Тут пишешь то, чо сейчас у тебя для converior<TLeft, TRight> написано
};
потом пишеш так:
template<typename TLeft, typename TRight> class convertor :
public SelectIf< convertor_default_implementation<TLeft, TRight>, cinveror_base,
IsStringType<TLeft>::Value && IsStringType<TRight>::Value >::Type {
private:
typedef SelectIf< convertor_default_implementation<TLeft, TRight>, cinveror_base,
IsStringType<TLeft>::Value && IsStringType<TRight>::Value >::Type TImplementation;
// Тут реализуешь нужные конструкторы, например такой:
convertor( const TLeft& left, const TRight& right ) : TImplementation( left, right ) {}
}
Всё!
если пользователь ничего не будет определять, что у него будет дефолтная реализация, для типов IsStringType будет реализация для строк, а если пользователь для какой-то пары специализирует convertor, то будет то, что он специализировал...
А>А что касается конкретно этого случая и предложенного к нему решения jazzer на макросах, то тут буст себя не с самой лучшей стороны показал. ИМХО. Хотя, каждому своё. Я, например, не макросоман, скорее макрософоб
Я вообзе-то имел в виду всякие там boost::mpl
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[9]: Специализация множеством типов
От:
Аноним
Дата:
20.09.07 07:13
Оценка:
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, <Аноним>, Вы писали:
А>>>>А на то предложение я ответил, что мне нужна специализация шаблона, в котором нету наследования. E>>>А зачем тебе она нужна? А>>Мне нужно специализировать convrtor<> для базовых строковых типов. Наследование — частный случай полной специализации шаблона convertor строковыми типами. Базовый шаблон не наследуется и не должен от чего-либо наследоваться.
К>Ещё раз спрашиваем: ЗАЧЕМ базовый шаблон должен не наследоваться.
Я думал, что сначала нужно отвечать на вопрос зачем тот или иной класс от чего-то наследовать.
По логике дизайна класса, ему незачем иметь какой бы то ни было базовый класс.
А корявить дизайн класса из базовых сервисов в пользу удобства реализации крайне не хотелось бы.
Вопрос сейчас в том, можно ли обойтись без наследования в исходном шаблоне.
По большому счёту, специализация строками может и не иметь базовый класс. Его можно слелать мембером. Тогда смысла в наследовании становится ещё меньше.
К>Это какие-то религиозные предубеждения, или какие-то тонкие игры с layout'ом объекта, или что?
Дело в банальном дизайне, который не хочется ущемлять из-за неудобств в реализации одной из специализаций шаблона строковыми типами.
Здравствуйте, Аноним, Вы писали:
А>Дело в банальном дизайне, который не хочется ущемлять из-за неудобств в реализации одной из специализаций шаблона строковыми типами.
Ну сделай тогда полем, тип которого выбирается при помощи той же шаблонной конструёвины, а свм convertor сделай просто редиректором вызовов. Типа повторяешь интерфейс и все вызовы перенаправляешь в методы поля.
Только я советую выбрать какую-нибудь такую конструкцию, чтобы пользователь мог добавить туда свои списочные специализации, а то у него могут анологичные проблемы возникнуть, вообще-то
Если не знаешь как это сделать без boost я напишу позже, когда будет немного времени.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, <Аноним>, Вы писали:
К>>Ещё раз спрашиваем: ЗАЧЕМ базовый шаблон должен не наследоваться. А>Я думал, что сначала нужно отвечать на вопрос зачем тот или иной класс от чего-то наследовать. А>По логике дизайна класса, ему незачем иметь какой бы то ни было базовый класс. А>А корявить дизайн класса из базовых сервисов в пользу удобства реализации крайне не хотелось бы.
А>Вопрос сейчас в том, можно ли обойтись без наследования в исходном шаблоне. А>По большому счёту, специализация строками может и не иметь базовый класс. Его можно слелать мембером. Тогда смысла в наследовании становится ещё меньше.
К>>Это какие-то религиозные предубеждения, или какие-то тонкие игры с layout'ом объекта, или что? А>Дело в банальном дизайне, который не хочется ущемлять из-за неудобств в реализации одной из специализаций шаблона строковыми типами.
Если коротко, то это и есть религиозные убеждения.
Наследование — это как инструмент для создания иерархии классов (т.е. выразительное средство архитектора), так и инструмент для кодирования (выразительное средство кодировщика).
Раз в С++ нет встроенной поддержки миксинов, то они имитируются наследованием от утилитарных баз (одних и тех же, специализированных, выбранных с помощью mpl и т.д.)
Причём, в отличие от иерархии, база-миксин (как правило) не фигурирует нигде как формальный тип ссылки/указателя.
Ну и помимо миксинов, есть ещё несколько технических ролей у наследования: например, определение layout'а структуры
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, <Аноним>, Вы писали:
К>>>Ещё раз спрашиваем: ЗАЧЕМ базовый шаблон должен не наследоваться. А>>Я думал, что сначала нужно отвечать на вопрос зачем тот или иной класс от чего-то наследовать. А>>По логике дизайна класса, ему незачем иметь какой бы то ни было базовый класс. А>>А корявить дизайн класса из базовых сервисов в пользу удобства реализации крайне не хотелось бы.
А>>Вопрос сейчас в том, можно ли обойтись без наследования в исходном шаблоне. А>>По большому счёту, специализация строками может и не иметь базовый класс. Его можно слелать мембером. Тогда смысла в наследовании становится ещё меньше.
К>>>Это какие-то религиозные предубеждения, или какие-то тонкие игры с layout'ом объекта, или что? А>>Дело в банальном дизайне, который не хочется ущемлять из-за неудобств в реализации одной из специализаций шаблона строковыми типами.
К>Если коротко, то это и есть религиозные убеждения.
К>Наследование — это как инструмент для создания иерархии классов (т.е. выразительное средство архитектора), так и инструмент для кодирования (выразительное средство кодировщика).
К>Раз в С++ нет встроенной поддержки миксинов, то они имитируются наследованием от утилитарных баз (одних и тех же, специализированных, выбранных с помощью mpl и т.д.) К>Причём, в отличие от иерархии, база-миксин (как правило) не фигурирует нигде как формальный тип ссылки/указателя.
К>Ну и помимо миксинов, есть ещё несколько технических ролей у наследования: например, определение layout'а структуры К>
Техническое наследование в базовом сервисе, имхо, не лучшее решение. Всё должно быть чётко и понятно, чтобы не возникало вопросов что за базовый класс, нужно ли его как-то учитывать или использовать. К тому же, распухшее объявление класса простоты тоже не прибавляет. В интерфейсных частях программы как раз ожидается увидеть решения архитектора, а не кодировщика.
Здравствуйте, <Аноним>, Вы писали:
А>Техническое наследование в базовом сервисе, имхо, не лучшее решение. Всё должно быть чётко и понятно, чтобы не возникало вопросов что за базовый класс, нужно ли его как-то учитывать или использовать. К тому же, распухшее объявление класса простоты тоже не прибавляет. В интерфейсных частях программы как раз ожидается увидеть решения архитектора, а не кодировщика.
Если это библиотека утилит — то она предназначена для кодировщиков, и решения там будут привязанные к идиоматике языка. Пример: boost.
А если это фреймворк, на основе которого строится приложение как единое целое — то конечно, акцент будет резко смещён в сторону архитекторской работы. Примеры: ACE, MFC.
Кстати о техническом наследовании.
Есть ведь ещё один способ решения
E>Если не знаешь как это сделать без boost я напишу позже, когда будет немного времени.
ясобственно у меня тут ребилд, так что могу объяснить подробно
Насколько я понял твою задачу, у тебя есть какой-то обобщенный конвертор, и пользователь может записывать специализации для различных пар типов.
При этом ты столкнулся с ситауцией, когда тебе хочется написать какие-то формальные правила, как конвертировать множества типов, а не только конкретные пары.
ИМХО у пользователей твоей библиотеки тоже может вознктнуть такая нужда. Раз уж она всё равно шаблонная, и всё равно завязана на специализации, то, ИМХО, стоит поставлять в ней сразу бесшовно расширяемый механизм для подобных описаний.
Вот мойнабросок такого механизма:
struct DafaultConvertorImplementationSelector {};
template<typename T> struct ConvertorTypeSelector { typedef DafaultConvertorImplementationSelector Selector; };
template<typename TFrom, typename TTo>
class DefaultConvertorImplementation {
// Тут твоя дефолтная реализация конвертора
};
template<typename TFrom, typename TTo,
typename TFromSelector = ConvertorTypeSelector<TFrom>::Selector,
typename TFromSelector = ConvertorTypeSelector<TTo>::Selector>
struct ConvertorImplementationSelector {
typedef DefaultConvertorImplementation<TForm, TTo> Convertor;
};
template<typename TFrom, typename TTo>
class Convertor {
ConvertorImplementationSelector<TFrom, TTo>::Convertor theConvertor;
public:
// Тут воспроизводишь интерфейс конвертора, раз уж наследоваться религия не позволяет, например так:void Convert( TFrom from, TTo to ) { theConvertor.Convert( from, to ); }
// Ну и так далее
};
// Теперь описываем новый тип конвертора, для простых строк:struct SimpleStringConvertorImplementationSelector {};
template<> struct ConvertorTypeSelector<const char*> { typedef SimpleStringConvertorImplementationSelector Selector; };
// И все другие простые строки...
// Теперь можем описать конвертор из строк в строкиclass SimpleStringConvertorImplementation {
// Тут реализуем тот конвертор, котрый ты называешь convertor_base
};
// И подключить его в нашу выбиралкуtemplate<typename TFrom, typename TTo>,
struct ConvertorImplementationSelector<TForm, TTo,
SimpleStringConvertorImplementationSelector, SimpleStringConvertorImplementationSelector> {
typedef SimpleStringConvertorImplementation Convertor;
};
// Мало того, теперь ты или пользователь библиотеки или ещё кто, например его пользователь
// Могут завести ещё один тип конверотра, например такой:struct IntegerNumbersConvertorImplementationSelector {};
template<> struct ConvertorTypeSelector<int> { typedef IntegerNumbersConvertorImplementationSelector Selector; };
template<> struct ConvertorTypeSelector<unsigned int> { typedef IntegerNumbersConvertorImplementationSelector Selector; };
template<> struct ConvertorTypeSelector<long> { typedef IntegerNumbersConvertorImplementationSelector Selector; };
// и так далее, что там надо/бывает
// Теперь пишем конвертор для чисел:template<typename TNumberFrom, typename TNumberTo>
class IntegerNumbersConvertor {
// ...
};
// И подключаем его в нашу выбиралкуtemplate<typename TFrom, typename TTo>,
struct ConvertorImplementationSelector<TForm, TTo,
IntegerNumbersConvertorImplementationSelector, IntegerNumbersConvertorImplementationSelector>: {
typedef IntegerNumbersConvertor<TFrom, TTo> Convertor;
};
// Мало того, наши возможности намного шире!!!
// Пишем, например, конвертор из простых строк в числаtemplate<typename TNumber>
class SimpleStringToNumberConvertor {
// ...
};
// И подключаем его в нашу выбиралкуtemplate<typename TFrom, typename TTo>,
struct ConvertorImplementationSelector<TForm, TTo,
SimpleStringConvertorImplementationSelector, IntegerNumbersConvertorImplementationSelector>: {
typedef IntegerNumbersConvertor<TFrom, TTo> Convertor;
};
// при этом это всё могут делать как клиенты, так и ты сам...
// Мало того, ты можешь пойти и ещё дальше, например так:template<typename TElement> struct ArryaConvertorImplementationSelector { typedef TElement Element; };
template<typedef TElement> struct ConvertorTypeSelector< std::vector<TElement> >
{ typedef ArryaConvertorImplementationSelector<TElement> Selector; };
template<typename TFromArray, typename TFromElement, typename TToArray, typename TToElement>
class DefaultArrayConvertor {
// Ну тут какая-то реализация
};
// И не забываем подключить его в нашу выбиралкуtemplate<typename TFrom, typename TTo>,
struct ConvertorImplementationSelector< TForm, TTo,
ArryaConvertorImplementationSelector<TFrom>, ArryaConvertorImplementationSelector<TTo> >: {
typedef DefaultArrayConvertor<TFrom, ArryaConvertorImplementationSelector<TFrom>::Element,
TTo, ArryaConvertorImplementationSelector<TTo>::Element> Convertor;
};
// Ну и так далее, на сколько хватит фантазии и потребностей и тебя и твоих клиентов :)
Заметь, что всё более или менее просто и совершенно легко расширяемо.
ИМХО если уж вы пошли в своей библиотеке на хитрые шаблоны с задаваемыми пользователями специализациями, то не стоит прикидываться девочкой, а стоит получать выгоды и удовольствие
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
К>Правда, доступ к конвертору становится более громоздким. Зато всё чисто!
Я так понимаю, что у конверотра очень простой интерфейс, так что можно написать ещё и простой шаблон-редиректор, который облегчит доступ:
template<typename X, typename Y> class convertor
{
public:
void convert( X x, Y y ) { the_convertor.convert( x, y ); }
private:
convertor_traits<X, Y>::convertor the_convertor;
};
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском