Специализация шаблонов по 2 параметрам
От: SVV Беларусь  
Дата: 18.02.16 12:20
Оценка:
Доброго всем времени суток,

есть такой класс:
template<class T>
class Test
{
public:
    template<class T2>
    Test(const T2* sz)
    {
        printf ("common version\n");
    }
    template<>
    Test(const char* sz)
    {
        printf ("T.a. str: %s\n", sz);
    }
    template<>
    Test(const wchar* sz)
    {
        printf ("T.w. str: %S\n", sz);
    }
protected:
};
template<>
Test<char>::Test<wchar>(const wchar* sz)// не компилируется
{
    printf ("a.w. str: %S\n", sz);
}

предположим, в качестве T будут использоваться типы char и wchar, как и в качестве T2. Как прописать специализацию не только по Т2?
Re: Специализация шаблонов по 2 параметрам
От: andyp  
Дата: 18.02.16 12:57
Оценка: 1 (1) +1
Здравствуйте, SVV, Вы писали:

SVV>Доброго всем времени суток,


SVV>есть такой класс:


SVV>
SVV>template<class T>
SVV>class Test
SVV>{
SVV>public:
SVV>    template<class T2>
SVV>    Test(const T2* sz)
SVV>    {
SVV>        printf ("common version\n");
SVV>    }
SVV>    template<>
SVV>    Test(const char* sz)
SVV>    {
SVV>        printf ("T.a. str: %s\n", sz);
SVV>    }
SVV>    template<>
SVV>    Test(const wchar* sz)
SVV>    {
SVV>        printf ("T.w. str: %S\n", sz);
SVV>    }
SVV>protected:
SVV>};
SVV>template<>
SVV>Test<char>::Test<wchar>(const wchar* sz)// не компилируется
SVV>{
SVV>    printf ("a.w. str: %S\n", sz);
SVV>}
SVV>


SVV>предположим, в качестве T будут использоваться типы char и wchar, как и в качестве T2. Как прописать специализацию не только по Т2?



template<> внутри класса не нужны.

Специализацию Test<char> придется определить полностью, так как для компилятора это отдельный класс, никак не связанный с общим шаблоном Test<T>, и никаких ожиданий по методам класса, которые должны быть определены, у него нет.
Re: Специализация шаблонов по 2 параметрам
От: andrey.desman  
Дата: 18.02.16 13:13
Оценка: 13 (3)
Здравствуйте, SVV, Вы писали:

SVV>предположим, в качестве T будут использоваться типы char и wchar, как и в качестве T2. Как прописать специализацию не только по Т2?


Так:

template<>
template<>
Test<char>::Test<wchar>(const wchar* sz)// компилируется
{
    printf ("a.w. str: %S\n", sz);
}


Только, как уже выше заметили, написать придется весь Test<char>.

UPD.
Хотя нет, вот такое работает: http://ideone.com/yAMokU
Отредактировано 18.02.2016 13:18 andrey.desman . Предыдущая версия .
Re: Специализация шаблонов по 2 параметрам
От: _NN_ www.nemerleweb.com
Дата: 18.02.16 13:17
Оценка: 1 (1)
Здравствуйте, SVV, Вы писали:

А что собственно нужно ?
Так что ли ?

#include <iostream>
using namespace std;

template<class T>
class Test
{
public:
    template<class T2>
    Test(const T2* sz)
    {
        printf ("common version\n");
    }
protected:
};

template<>
template<>
Test<char>::Test<wchar_t>(const wchar_t* sz)
{
    printf ("a.w. str: %S\n", sz);
}

template<>
template<>
Test<wchar_t>::Test<char>(const char* sz)
{
    printf ("w.a str: %s\n", sz);
}

int main() {
    Test<char> a("A");
    Test<char> b(L"B");
    Test<wchar_t> c("C");
    Test<wchar_t> d(L"D");

    return 0;
}
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: Специализация шаблонов по 2 параметрам
От: rg45 СССР  
Дата: 18.02.16 13:26
Оценка:
Здравствуйте, andyp, Вы писали:

A>Специализацию Test<char> придется определить полностью, так как для компилятора это отдельный класс...


На самом деле, не обязательно. В С++ существует и такая форма специализации для функций-членов шаблонных классов:

template <typename T>
class A
{
public:

   void foo(int);

};
template <>
void A<double>::foo(int) {/*...*/}

template <>
void A<std::string>::foo(int) {/*...*/}

template <>
void A<bool>::foo(int) {/*...*/}


И это именно специализация функций-членов, без специализации самого шаблонного класса.

Такая форма специализации, конечно же, допустима и для конструкторов. Поэтому в исходном примере достаточно просто заменить специализацию конструкторов на перегрузку:

template<class T>
class Test
{
public:
    template <class T2>
        Test(const T2* sz)
    {
        printf ("common version\n");
    }
    Test(const char* sz)
    {
        printf ("T.a. str: %s\n", sz);
    }
    Test(const wchar_t* sz)
    {
        printf ("T.w. str: %S\n", sz);
    }
protected:
};
// Поная специализация конструктора без специализации самого шаблонного класса:
template<>
Test<char>::Test(const wchar_t* sz)// компилируется
{
    printf ("a.w. str: %S\n", sz);
}
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 18.02.2016 13:38 rg45 . Предыдущая версия . Еще …
Отредактировано 18.02.2016 13:27 rg45 . Предыдущая версия .
Re[2]: Специализация шаблонов по 2 параметрам
От: SVV Беларусь  
Дата: 18.02.16 13:29
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Здравствуйте, SVV, Вы писали:


_NN>А что собственно нужно ?

_NN>Так что ли ?

_NN>
_NN>#include <iostream>
_NN>using namespace std;

_NN>template<class T>
_NN>class Test
_NN>{
_NN>public:
_NN>    template<class T2>
_NN>    Test(const T2* sz)
_NN>    {
_NN>        printf ("common version\n");
_NN>    }
_NN>protected:
_NN>};

_NN>template<>
_NN>template<>
_NN>Test<char>::Test<wchar_t>(const wchar_t* sz)//error C2039: 'Test<T>' : is not a member of 'Test<T>'
_NN>{
_NN>    printf ("a.w. str: %S\n", sz);
_NN>}

_NN>template<>
_NN>template<>
_NN>Test<wchar_t>::Test<char>(const char* sz)
_NN>{
_NN>    printf ("w.a str: %s\n", sz);
_NN>}

_NN>int main() {
_NN>    Test<char> a("A");
_NN>    Test<char> b(L"B");
_NN>    Test<wchar_t> c("C");
_NN>    Test<wchar_t> d(L"D");

_NN>    return 0;
_NN>}
_NN>

да, так. только это не прокатывает. vs2012 update5
Re[3]: Специализация шаблонов по 2 параметрам
От: andyp  
Дата: 18.02.16 14:08
Оценка:
Здравствуйте, rg45, Вы писали:

R>На самом деле, не обязательно. В С++ существует и такая форма специализации для функций-членов шаблонных классов:

R>И это именно специализация функций-членов, без специализации самого шаблонного класса.

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

R>Такая форма специализации, конечно же, допустима и для конструкторов. Поэтому в исходном примере достаточно просто заменить специализацию конструкторов на перегрузку:


  Код
R>
R>template<class T>
R>class Test
R>{
R>public:
R>    template <class T2>
R>        Test(const T2* sz)
R>    {
R>        printf ("common version\n");
R>    }
R>    Test(const char* sz)
R>    {
R>        printf ("T.a. str: %s\n", sz);
R>    }
R>    Test(const wchar_t* sz)
R>    {
R>        printf ("T.w. str: %S\n", sz);
R>    }
R>protected:
R>};
R>// Поная специализация конструктора без специализации самого шаблонного класса:
R>template<>
R>Test<char>::Test(const wchar_t* sz)// компилируется
R>{
R>    printf ("a.w. str: %S\n", sz);
R>}
R>


Занятный пример. Это вроде компилируется, но на мой взгляд ломает ODR. Компиляторам вроде бы можно не отлавливать подобное. См. дискуссию здесь:
http://stackoverflow.com/questions/26305368/c-define-member-function-outside-template-class-but-in-header

Я бы так точно не делал.


Вы правы, здесь все нормально, просто это специализации отдельных методов класса.
Отредактировано 18.02.2016 20:58 andyp . Предыдущая версия .
Re[3]: Специализация шаблонов по 2 параметрам
От: _NN_ www.nemerleweb.com
Дата: 18.02.16 14:28
Оценка:
Здравствуйте, SVV, Вы писали:

SVV>да, так. только это не прокатывает. vs2012 update5

Можно через функции ?

#include <iostream>
using namespace std;

template<class T>
class Test
{
public:
    template<class T2>
    Test(const T2* sz)
    {
        f(sz);
    }

    template<class T2>
    void f(const T2* sz) 
    {
        printf ("Common");
    }
    
protected:
};

template<>
template<>
void Test<char>::f<wchar_t>(const wchar_t* sz)
{
    printf ("a.w. str: %S\n", sz);
}

template<>
template<>
void Test<wchar_t>::f<char>(const char* sz)
{
    printf ("w.a str: %s\n", sz);
}

int main() {
    Test<char> a("A");
    Test<char> b(L"B");
    Test<wchar_t> c("C");
    Test<wchar_t> d(L"D");

    return 0;
}
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: Специализация шаблонов по 2 параметрам
От: _NN_ www.nemerleweb.com
Дата: 18.02.16 20:30
Оценка: 3 (1)
Здравствуйте, SVV, Вы писали:

SVV>да, так. только это не прокатывает. vs2012 update5


Убрать нужно скобки:
Test<char>::Test

#include <iostream>
using namespace std;

template<class T>
class Test
{
public:
    template<class T2>
    Test(const T2* sz)
    {
        printf ("common version\n");
    }
protected:
};

template<>
template<>
Test<char>::Test(const wchar_t* sz)
{
    printf ("a.w. str: %S\n", sz);
}

template<>
template<>
Test<wchar_t>::Test(const char* sz)
{
    printf ("w.a str: %s\n", sz);
}

int main() {
    Test<char> a("A");
    Test<char> b(L"B");
    Test<wchar_t> c("C");
    Test<wchar_t> d(L"D");

    return 0;
}


Microsoft (R) C/C++ Optimizing Compiler Version 17.00.50727.1 for x64
Copyright (C) Microsoft Corporation. All rights reserved.

a.cpp
Microsoft (R) Incremental Linker Version 11.00.50727.1
Copyright (C) Microsoft Corporation. All rights reserved.

/out:a.exe
a.obj

http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[4]: Специализация шаблонов по 2 параметрам
От: SVV Беларусь  
Дата: 19.02.16 01:29
Оценка:
_NN>Убрать нужно скобки:
вот теперь прокатило, спасибо!
Re[2]: Специализация шаблонов по 2 параметрам
От: Erop Россия  
Дата: 19.02.16 19:04
Оценка: +1
Здравствуйте, andyp, Вы писали:

A>Специализацию Test<char> придется определить полностью, так как для компилятора это отдельный класс, никак не связанный с общим шаблоном Test<T>, и никаких ожиданий по методам класса, которые должны быть определены, у него нет.


Можно же специализировать только один метод?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Специализация шаблонов по 2 параметрам
От: Erop Россия  
Дата: 19.02.16 19:08
Оценка:
Здравствуйте, SVV, Вы писали:

SVV>предположим, в качестве T будут использоваться типы char и wchar, как и в качестве T2. Как прописать специализацию не только по Т2?


Просто интересно, а зачем это надо?
Ну, грубо говоря, если мы как-то особо работаем с whar_t, например, и как-то ещё иначе особо с char, то может лучше иметь шаблон, кторй работает как-то в целом, а для этих типав специализирован, а потом уже на этом шаблоне реализовывать конструктор class Test?

То есть, я вполне верю, что есть ситуации, когда надо и так, как надо тебе, но мне интересно каковы они.
Не поделишься?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Специализация шаблонов по 2 параметрам
От: SVV Беларусь  
Дата: 20.02.16 10:14
Оценка: 12 (1)
Здравствуйте, 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 а не больше.
Отредактировано 20.02.2016 10:15 SVV . Предыдущая версия .
Re[3]: Специализация шаблонов по 2 параметрам
От: Кодт Россия  
Дата: 20.02.16 11:07
Оценка:
Здравствуйте, SVV, Вы писали:

SVV>если делается класс для работы как с char так и с wchar_t то конструкторов должно быть минимум 4:


Как насчёт подумать в такую сторону?
template<class T> class Str {
public:
  template<class T2>
  Str(const T2* src) : data_( allocate_or_point<T>(src) ), deleter_( delete_or_nothing<T,T2> ) {}
private:
  T* data_;
  void (*deleter_)(T*);
};
Перекуём баги на фичи!
Re[3]: Специализация шаблонов по 2 параметрам
От: Erop Россия  
Дата: 20.02.16 23:42
Оценка:
Здравствуйте, 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?..
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Специализация шаблонов по 2 параметрам
От: SVV Беларусь  
Дата: 21.02.16 07:45
Оценка:
Здравствуйте, 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 только немного по-другому будет работа со строками происходить. как буду обобщать еще не знаю.
Отредактировано 21.02.2016 7:47 SVV . Предыдущая версия .
Re[4]: Специализация шаблонов по 2 параметрам
От: SVV Беларусь  
Дата: 21.02.16 07:52
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, SVV, Вы писали:


SVV>>если делается класс для работы как с char так и с wchar_t то конструкторов должно быть минимум 4:


К>Как насчёт подумать в такую сторону?

К>
К>template<class T> class Str {
К>public:
К>  template<class T2>
К>  Str(const T2* src) : data_( allocate_or_point<T>(src) ), deleter_( delete_or_nothing<T,T2> ) {}
К>private:
К>  T* data_;
К>  void (*deleter_)(T*);
К>};
К>

я не совсем понял намёк, сорри. Мой уровень не достаточен. Но смысл в том чтобы сделать объект класса минимального размера. Выделать 4 байта под deleter пока не хочется. Но про allocator/deallocator уже что-то думается. Надо будет как-то через параметр шаблона что-то передавать и не сохраняя как член класса использовать в методах. Если это возможно.
Re[5]: Специализация шаблонов по 2 параметрам
От: Кодт Россия  
Дата: 21.02.16 11:10
Оценка: 3 (1)
Здравствуйте, SVV, Вы писали:

SVV>я не совсем понял намёк, сорри. Мой уровень не достаточен. Но смысл в том чтобы сделать объект класса минимального размера. Выделать 4 байта под deleter пока не хочется. Но про allocator/deallocator уже что-то думается. Надо будет как-то через параметр шаблона что-то передавать и не сохраняя как член класса использовать в методах. Если это возможно.


Намёк такой, что сделать класс сам по себе минимально специализируемым. Один шаблон и всё.
А места для конкретизации вынести за его пределы.

Я не знаю, нужно ли кастомизировать владение. Это примерно по аналогии с макросами A2W и т.п. в MFC/ATL/WTL — если строка того же типа, то прозрачно держим указатель на оригинал, а если другого — создаём копию, которую потом удалим.
Если нужно — тогда будет деаллокатор-или-пусто. В конце концов, это не 4 байта, а 1 (булев флажок), — хотя всё равно, с учётом выравнивания, вырастет до 4 байтов.
Если копия строки создаётся всегда, — то не нужно, делаем безусловный деструктор.
Перекуём баги на фичи!
Re[6]: Специализация шаблонов по 2 параметрам
От: SVV Беларусь  
Дата: 22.02.16 09:33
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, SVV, Вы писали:


SVV>>я не совсем понял намёк, сорри. Мой уровень не достаточен. Но смысл в том чтобы сделать объект класса минимального размера. Выделать 4 байта под deleter пока не хочется. Но про allocator/deallocator уже что-то думается. Надо будет как-то через параметр шаблона что-то передавать и не сохраняя как член класса использовать в методах. Если это возможно.


К>Намёк такой, что сделать класс сам по себе минимально специализируемым. Один шаблон и всё.

К>А места для конкретизации вынести за его пределы.

К>Я не знаю, нужно ли кастомизировать владение. Это примерно по аналогии с макросами A2W и т.п. в MFC/ATL/WTL — если строка того же типа, то прозрачно держим указатель на оригинал, а если другого — создаём копию, которую потом удалим.

К>Если нужно — тогда будет деаллокатор-или-пусто. В конце концов, это не 4 байта, а 1 (булев флажок), — хотя всё равно, с учётом выравнивания, вырастет до 4 байтов.
К>Если копия строки создаётся всегда, — то не нужно, делаем безусловный деструктор.
на длину строки отведено 4 байта. некоторые типы строк всегда будут содержать только указатель и не освобождать данные. в таких случаях char -> wchar преобразование невозможно. в других строках старший бит длины определяет надо ли освобождать данные. Таким образом, длина строки только 2^31, чего в большинстве случаев достаточно.
Re[7]: Специализация шаблонов по 2 параметрам
От: Кодт Россия  
Дата: 22.02.16 15:13
Оценка:
Здравствуйте, SVV, Вы писали:

SVV>на длину строки отведено 4 байта. некоторые типы строк всегда будут содержать только указатель и не освобождать данные. в таких случаях char -> wchar преобразование невозможно. в других строках старший бит длины определяет надо ли освобождать данные. Таким образом, длина строки только 2^31, чего в большинстве случаев достаточно.


Вот это вообще не понял, при чём. Строка с префиксом-длиной, как в BSTR или паскале-дельфи? И с политиками времени жизни, как в ObjC?

Ну так тем лучше. Хранить только указатель на строку, удалять или нет с оглядкой на флажки в префиксе.
Тогда всё, что нужно — это написать 4 функции копирования.
Перекуём баги на фичи!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.