SVV>предположим, в качестве T будут использоваться типы char и wchar, как и в качестве T2. Как прописать специализацию не только по Т2?
template<> внутри класса не нужны.
Специализацию Test<char> придется определить полностью, так как для компилятора это отдельный класс, никак не связанный с общим шаблоном Test<T>, и никаких ожиданий по методам класса, которые должны быть определены, у него нет.
Здравствуйте, SVV, Вы писали:
SVV>предположим, в качестве T будут использоваться типы char и wchar, как и в качестве T2. Как прописать специализацию не только по Т2?
И это именно специализация функций-членов, без специализации самого шаблонного класса.
Такая форма специализации, конечно же, допустима и для конструкторов. Поэтому в исходном примере достаточно просто заменить специализацию конструкторов на перегрузку:
Здравствуйте, rg45, Вы писали: R>На самом деле, не обязательно. В С++ существует и такая форма специализации для функций-членов шаблонных классов: R>И это именно специализация функций-членов, без специализации самого шаблонного класса.
Про это я знал, но ТС определил конструкторы в теле класса, а затем вне тела для специализации. Поэтому я и подумал, что ему потребуется определить специализацию. R>Такая форма специализации, конечно же, допустима и для конструкторов. Поэтому в исходном примере достаточно просто заменить специализацию конструкторов на перегрузку:
Здравствуйте, andyp, Вы писали:
A>Специализацию Test<char> придется определить полностью, так как для компилятора это отдельный класс, никак не связанный с общим шаблоном Test<T>, и никаких ожиданий по методам класса, которые должны быть определены, у него нет.
Можно же специализировать только один метод?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, SVV, Вы писали:
SVV>предположим, в качестве T будут использоваться типы char и wchar, как и в качестве T2. Как прописать специализацию не только по Т2?
Просто интересно, а зачем это надо?
Ну, грубо говоря, если мы как-то особо работаем с whar_t, например, и как-то ещё иначе особо с char, то может лучше иметь шаблон, кторй работает как-то в целом, а для этих типав специализирован, а потом уже на этом шаблоне реализовывать конструктор class Test?
То есть, я вполне верю, что есть ситуации, когда надо и так, как надо тебе, но мне интересно каковы они.
Не поделишься?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, SVV, Вы писали:
SVV>>предположим, в качестве T будут использоваться типы char и wchar, как и в качестве T2. Как прописать специализацию не только по Т2?
E>Просто интересно, а зачем это надо? E>Ну, грубо говоря, если мы как-то особо работаем с whar_t, например, и как-то ещё иначе особо с char, то может лучше иметь шаблон, кторй работает как-то в целом, а для этих типав специализирован, а потом уже на этом шаблоне реализовывать конструктор class Test?
E>То есть, я вполне верю, что есть ситуации, когда надо и так, как надо тебе, но мне интересно каковы они. E>Не поделишься?
Делюсь:
если делается класс для работы как с char так и с wchar_t то конструкторов должно быть минимум 4:
для char версии класса:
Test(const char *) — обычная инициализация
Test(const wchar_t *) — инициализация конвертацией wide строки в char
для wchar_t версии класса:
Test(const char *) — инициализация конвертацией char строки в wide
Test(const wchar_t *) — обычная инициализация
те же минимум 4 operator= (&), operator=(&&) и конструкторы Test (&&)
и да, основной функционал запихнул в глобальные inline функции. Надеюсь, компилятор прооптимизирует. Просто сейчас есть TestA версия и TestW версия отдельно, и я смотрю что они сильно похожи, правишь что-то в одном классе и надо лезть аналогичные правки делать в другом. И хорошо если классов 2 а не больше.
Здравствуйте, SVV, Вы писали:
SVV>Делюсь: SVV>если делается класс для работы как с char так и с wchar_t то конструкторов должно быть минимум 4: SVV>для char версии класса: SVV>Test(const char *) — обычная инициализация SVV>Test(const wchar_t *) — инициализация конвертацией wide строки в char SVV>для wchar_t версии класса: SVV>Test(const char *) — инициализация конвертацией char строки в wide SVV>Test(const wchar_t *) — обычная инициализация
SVV>те же минимум 4 operator= (&), operator=(&&) и конструкторы Test (&&)
Не ясно зачем тут вообще шаблонный конструктор, если честно... :xz;
SVV>и да, основной функционал запихнул в глобальные inline функции. Надеюсь, компилятор прооптимизирует. Просто сейчас есть TestA версия и TestW версия отдельно, и я смотрю что они сильно похожи, правишь что-то в одном классе и надо лезть аналогичные правки делать в другом. И хорошо если классов 2 а не больше.
А как предполагается обобщать, если классов больше? Имеется в виду что есть ещё и TryA и TryW, DoA и DoW и т. д, или что, кроме A и W есть X, Y, Z?..
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, SVV, Вы писали:
SVV>>Делюсь: SVV>>если делается класс для работы как с char так и с wchar_t то конструкторов должно быть минимум 4: SVV>>для char версии класса: SVV>>Test(const char *) — обычная инициализация SVV>>Test(const wchar_t *) — инициализация конвертацией wide строки в char SVV>>для wchar_t версии класса: SVV>>Test(const char *) — инициализация конвертацией char строки в wide SVV>>Test(const wchar_t *) — обычная инициализация
SVV>>те же минимум 4 operator= (&), operator=(&&) и конструкторы Test (&&)
E>Не ясно зачем тут вообще шаблонный конструктор, если честно... :xz;
Верно, достаточно прописать специализацию для Test<char> и Test<wchar>.
E>А как предполагается обобщать, если классов больше? Имеется в виду что есть ещё и TryA и TryW, DoA и DoW и т. д, или что, кроме A и W есть X, Y, Z?..
скорее что-то кроме A и W. То есть это опять A и W только немного по-другому будет работа со строками происходить. как буду обобщать еще не знаю.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, SVV, Вы писали:
SVV>>если делается класс для работы как с char так и с wchar_t то конструкторов должно быть минимум 4:
К>Как насчёт подумать в такую сторону? К>
я не совсем понял намёк, сорри. Мой уровень не достаточен. Но смысл в том чтобы сделать объект класса минимального размера. Выделать 4 байта под deleter пока не хочется. Но про allocator/deallocator уже что-то думается. Надо будет как-то через параметр шаблона что-то передавать и не сохраняя как член класса использовать в методах. Если это возможно.
Здравствуйте, SVV, Вы писали:
SVV>я не совсем понял намёк, сорри. Мой уровень не достаточен. Но смысл в том чтобы сделать объект класса минимального размера. Выделать 4 байта под deleter пока не хочется. Но про allocator/deallocator уже что-то думается. Надо будет как-то через параметр шаблона что-то передавать и не сохраняя как член класса использовать в методах. Если это возможно.
Намёк такой, что сделать класс сам по себе минимально специализируемым. Один шаблон и всё.
А места для конкретизации вынести за его пределы.
Я не знаю, нужно ли кастомизировать владение. Это примерно по аналогии с макросами A2W и т.п. в MFC/ATL/WTL — если строка того же типа, то прозрачно держим указатель на оригинал, а если другого — создаём копию, которую потом удалим.
Если нужно — тогда будет деаллокатор-или-пусто. В конце концов, это не 4 байта, а 1 (булев флажок), — хотя всё равно, с учётом выравнивания, вырастет до 4 байтов.
Если копия строки создаётся всегда, — то не нужно, делаем безусловный деструктор.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, SVV, Вы писали:
SVV>>я не совсем понял намёк, сорри. Мой уровень не достаточен. Но смысл в том чтобы сделать объект класса минимального размера. Выделать 4 байта под deleter пока не хочется. Но про allocator/deallocator уже что-то думается. Надо будет как-то через параметр шаблона что-то передавать и не сохраняя как член класса использовать в методах. Если это возможно.
К>Намёк такой, что сделать класс сам по себе минимально специализируемым. Один шаблон и всё. К>А места для конкретизации вынести за его пределы.
К>Я не знаю, нужно ли кастомизировать владение. Это примерно по аналогии с макросами A2W и т.п. в MFC/ATL/WTL — если строка того же типа, то прозрачно держим указатель на оригинал, а если другого — создаём копию, которую потом удалим. К>Если нужно — тогда будет деаллокатор-или-пусто. В конце концов, это не 4 байта, а 1 (булев флажок), — хотя всё равно, с учётом выравнивания, вырастет до 4 байтов. К>Если копия строки создаётся всегда, — то не нужно, делаем безусловный деструктор.
на длину строки отведено 4 байта. некоторые типы строк всегда будут содержать только указатель и не освобождать данные. в таких случаях char -> wchar преобразование невозможно. в других строках старший бит длины определяет надо ли освобождать данные. Таким образом, длина строки только 2^31, чего в большинстве случаев достаточно.
Здравствуйте, SVV, Вы писали:
SVV>на длину строки отведено 4 байта. некоторые типы строк всегда будут содержать только указатель и не освобождать данные. в таких случаях char -> wchar преобразование невозможно. в других строках старший бит длины определяет надо ли освобождать данные. Таким образом, длина строки только 2^31, чего в большинстве случаев достаточно.
Вот это вообще не понял, при чём. Строка с префиксом-длиной, как в BSTR или паскале-дельфи? И с политиками времени жизни, как в ObjC?
Ну так тем лучше. Хранить только указатель на строку, удалять или нет с оглядкой на флажки в префиксе.
Тогда всё, что нужно — это написать 4 функции копирования.
Ложки нет (С) Из наставлений для Нео по шаблонному программированию.
Никаких специализаций шаблонов в С++ не существует. Шаблонов тоже не существует. Т.е. названия такие есть, но они суть умозрительные категории — не обращай на них внимание. ты должен помнить, что
а) шаблон это что-то вроде макроса, только строго типизированный
б) сам шаблон не порождает кода
в) там, где ты используешь шаблон — происходит инстанцирование класса
г) инстанции класса в реальности существуют. Шаблоны — нет! Т.е. std::vector<int> в точке инстанцирования точно существует. Но это некий отдельный класс, который не имеет отношения к исходному шаблону. Связь между шаблоном и инстанциеей односторонняя!!!
д) Частичная специализация шаблона для класса — это отдельный шаблон. В нём может быть всё по другому, правил нет!!!
наподобие перегруженных функций. test (int) и test (int, void*) — это две разные функции с одинаковым названием.
e) Если частичная специализация шаблона для класса задаёт один-единственный класс, а не семейство классов, то он связан с материнским шаблоном так же, как и инстанция шаблона связана с ним — никак!!! Компилер считает их разными шаблонами с одним именем, и при встрече инстанции пытается дедуктивно вывести, какое из твоих определений подставить
ещё раз — специализация шаблона может быть другой по смыслу. вплоть до смешного.
//класс, который моет окнаtemplate<typename WindowType> Wash {
public:
void Start(WindowType & arg) {StartWash(arg);}
private:
void StartWash(WindowType & arg);
}
//класс, который запускает ракетыtemplate<typename Rocket1, typename Rocket2> Wash {
public:
void start(Rocket1 & rocket) {LaunchRocket(rocket);}
void start(Rocket2 & rocket) {LaunchRocket(rocket);}
private:
void LaunchRocket(Rocket1 & rocket);
void LaunchRocket(Rocket2 & rocket);
}
class Window {};
class RoundWindow : public Window {};
class TriangleWindow : public Window {};
void int main(int argc, char *argv[])
{
RoundWindow rw;
TriangleWindow tw;
Wash<RoundWindow> wash1;
Wash<TriangleWindow> wash2;
Wash<RoundWindow, TriangleWindow> wash3;
wash1->start(rw); //помыли круглое окно
wash2->start(tw); //помыли треугольное окно
wash3->start(tw); //запустили ракету в космос
}
Здравствуйте, _NN_, Вы писали:
_NN>Здравствуйте, SVV, Вы писали:
SVV>>да, так. только это не прокатывает. vs2012 update5
_NN>Убрать нужно скобки: _NN>Test<char>::Test
_NN>
должна быть в h файле (иначе при линковке символ не виден везде где нужен).
Таким образом, если в специализации Init (т.е. в h файле) я использую конструктор (специализация которого в cpp файле далее и "сейчас" не доступна), то возникает ошибка компиляции (в cpp файле компилятор не принимает специализацию утверждая что там уже лишнее). Вероятно это потому что класс в h файле компилятор создал как мог. Можно ли как-то перенести специализацию (констректора например) в определение класса (в h файле) или сделать что-то типа "forward declaration"?
P.S. в классе Test<char>::Init понадобилось использовать класс Test<wchar>::Test... Обойти можно, но получается не очень красиво
SVV>должна быть в h файле (иначе при линковке символ не виден везде где нужен).
Тут что-то не так...
SVV>Можно ли как-то перенести специализацию (констректора например) в определение класса (в h файле) или сделать что-то типа "forward declaration"?
Спс. Сразу попробовал в определение класса в h файл — не прокатило. Видимо нельзя там template<>template<> прописывать, а вот если после определения класса в h файле, то прокатило!
Если Т=char, то конструктор должен быть только для NotT=wchar (не для char)
Если Т=wchar то конструктор должен быть только для NotT=char (не для wchar)
если
template<>template<>Test<char>::Test(char) просто не реализовывать, то ошибка появляется только на этапе линковки. А хотелось бы чтобы она была на этапе компиляции. Можно так сделать?
Я бы и рад обойтись вообще без шаблонов тут, но не знаю как.
Вот если бы можно было что-то типа
#if sizeof(T)==1
или
#if typeof(T)==char
...
Здравствуйте, SVV, Вы писали: SVV>Я бы и рад обойтись вообще без шаблонов тут, но не знаю как. SVV>Вот если бы можно было что-то типа SVV>#if sizeof(T)==1 SVV>или SVV>#if typeof(T)==char SVV>...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском