Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

template<> Вопрос для профессионалов С++.

3
30 марта 2003 года
Green
4.8K / / 20.01.2000
Есть такой код:

#include <iostream>
using namespace std;

template <class T>
void get() {
cout << 2;
}

template<>
void get<char>() {
cout << 5;
}

template<>
void get<int>() {
cout << 4;
}

int main() {
get<char>();
get<int>();
get<double>();

return 0;
}

Предполагалось, что на экран выведется:
5
4
2
Но в реальности выводиться:
5
5
5
При этом, если поменять местами частные спецификации для char и int, т.е. записать:

template <class T>
void get() {
cout << 2;
}

template<> // местоположение
void get<int>() { // в коде изменено
cout << 4; //
} //

template<> // местоположение
void get<char>() { // в коде изменено
cout << 5; //
} //

int main() {
get<char>();
get<int>();
get<double>();

return 0;
}

то будет выводиться уже:
4
4
4

ПОЧЕМУ? Почему не работает, как предполагалось?

P.S. Компилятор из VS6.0
2.0K
30 марта 2003 года
segev
67 / / 19.01.2003
Green
Пример кода достаточно бессмысленный т.к. использование шаблонов функций предполагает наличие в ее заголовке параметров, зависящих от типа T.
Например
template<class T> void get(T t) {...}
Именно по фактическим типам параметров заголовка компилятор узнает какую специализацию следует генерировать при вызове функции. Что делает компилятор в твоем случае, трудно сказать. Могу высказать версию, что указание специализации при вызове фукнкций из main он просто игнорирует, а вызов get() разрешает, выбрав первую попавшуюся частную специализацию.
3
30 марта 2003 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by segev

Пример кода достаточно бессмысленный



Ну на счет бессмысленности с точки зрения программиста, это мне решать :о)
Мне такой код, при условии его работоспособности, упростил бы жизнь.

Цитата:
Originally posted by segev
т.к. использование шаблонов функций предполагает наличие в ее заголовке параметров, зависящих от типа T.
Например
template<class T> void get(T t) {...}



Честно говоря, не нашел точного указания о том, что в заголовке должны быть "параметры зависящие от T", т.е. от параметра шаблона.

Цитата:
Originally posted by segev
Именно по фактическим типам параметров заголовка компилятор узнает какую специализацию следует генерировать при вызове функции.



Не совсем так. MSDN "Working with Function Templates":

Explicit specification of the template arguments for a function template is allowed. For example:

template<class T> void f(T) {...}
void g(char j) {
f<int>(j); //generate the specialization f(int)
}

Цитата:
Originally posted by segev
Что делает компилятор в твоем случае, трудно сказать. Могу высказать версию, что указание специализации при вызове фукнкций из main он просто игнорирует, а вызов get() разрешает, выбрав первую попавшуюся частную специализацию.



Видимо так. Но почему? Это соответствует стандарту языка или очередной "баг" (отличие от стандарта) от фирмы M$, как, например, отсутствие частичной спецификации шаблонов, инстанирование шаблона шаблоном (хотя в VC++.NET это уже есть) и т.п.?

2.0K
31 марта 2003 года
segev
67 / / 19.01.2003
Green
Цитата:

Ну на счет бессмысленности с точки зрения программиста, это мне решать :о)
Мне такой код, при условии его работоспособности, упростил бы жизнь.


Решай сам конечно, я просто не понимаю чем может упростить жизнь подобный код: какая разница, написать
get<char>();
get<int>();
или
get_char();
get_int();
Откуда такая тяга к шаблонам, если можно обойтись без них ?

Цитата:

Не совсем так. MSDN "Working with Function Templates":

Explicit specification of the template arguments for a function template is allowed. For example:

template<class T> void f(T) {...}
void g(char j) {
f<int>(j); //generate the specialization f(int)
}


Ты не обратил внимания на эту строчку ?
template<class T> void f(T) {...}
Это как раз то, о чем я писал.
А явное указание используется для того чтобы преобразовать j из char в int. С таким же успехом можно было написать.
f((int)j)
вместо
f<int>(j)

Да, VC 6 не блещет поддержкой шаблонов, но в данном случае его поведение вполне разумно.

3
31 марта 2003 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by segev
Решай сам конечно, я просто не понимаю чем может упростить жизнь подобный код: какая разница, написать
get<char>();
get<int>();
или
get_char();
get_int();
Откуда такая тяга к шаблонам, если можно обойтись без них ?



Это был лишь пример кода. Без контекста, видимо, действительно трудно понять необходимость и упрощение при использовании шаблонов, но если ты знаком с паттерном "стратегия", тогда преимущество очевидно.

Цитата:
Originally posted by segev
Ты не обратил внимания на эту строчку ?
template<class T> void f(T) {...}
Это как раз то, о чем я писал.
А явное указание используется для того чтобы преобразовать j из char в int. С таким же успехом можно было написать.
f((int)j)
вместо
f<int>(j)

Да, VC 6 не блещет поддержкой шаблонов, но в данном случае его поведение вполне разумно.



Нет. Не разумно. В более продвинутых компиляторах, например в VS.NET 2003, мой пример корректно работает. Т.о. моя проблема - это баг VC++6.0

2.0K
01 апреля 2003 года
segev
67 / / 19.01.2003
Green
Цитата:

Это был лишь пример кода. Без контекста, видимо, действительно трудно понять необходимость и упрощение при использовании шаблонов, но если ты знаком с паттерном "стратегия", тогда преимущество очевидно.


Не знаю, что за "стратегия" такая. Просвети, если не трудно.
Контекст здесь не причем. Смысл использования шаблонов с частными специализациями в том, что компилятор сам выбирает нужную реализацию в зависимости от типа аргументов. А ты выбираешь ее ручками. По смыслу это тоже самое, что создать несколько функций с разными именами. Поэтому я и написал, что пример бессмысленный в части применения шаблонов (и в чем я до сих по уверен :) ).

Чтобы перевести эту бесплодную дискуссию в конструктивное русло могу предложить изменить заголовок вот так:
template<class T> void get(T* = NULL) {...};
Думаю будет работать.

2.0K
01 апреля 2003 года
udgine
20 / / 04.03.2003
Цитата:
Originally posted by Green
Есть такой код:

#include <iostream>
using namespace std;

template <class T>
void get() {
cout << 2;
}

template<>
void get<char>() {
cout << 5;
}

template<>
void get<int>() {
cout << 4;
}

int main() {
get<char>();
get<int>();
get<double>();

return 0;
}



Немного не правильное использование шаблона функции. Такое использование правильно для шаблона класса. Для функции же правильно передача шаблона через фактический параметр, а не через <>:

template <class T>
void get(T i) {

....

}

int main() {
char a;
get(a);
int b
get(b);
double c
get(с);

return 0;
}

Да и еще одно - из свойств шаблона функций:

Список параметров шаблона функции не может быть пустым, т.к. при этом теряется возможность параметризации и шаблон функции становится обычным определением конкретной функции.

А вообще твой пример несколько не понятен, т.е. ты в принципе можешь воспользоваться перегрузкой функций.

3
01 апреля 2003 года
Green
4.8K / / 20.01.2000
Коллеги, я уже докопался до сути:
это всё баг VC++6.0, в .NET 2003 все отлично работает!

Цитата:
Originally posted by udgine

Немного не правильное использование шаблона функции. Такое использование правильно для шаблона класса. Для функции же правильно передача шаблона через фактический параметр, а не через <>:



Где такое сказанно? В спецификации языка этого нет.

Цитата:
Originally posted by udgine

Список параметров шаблона функции не может быть пустым, т.к. при этом теряется возможность параметризации и шаблон функции становится обычным определением конкретной функции.



Список параметров шаблона или список аргументов функции?

Цитата:
Originally posted by udgine

А вообще твой пример несколько не понятен, т.е. ты в принципе можешь воспользоваться перегрузкой функций.



Поверьте, я знаю, что такое перегрузака. :о)
А вы знаете, что такое паттерны и в частности паттерн "стратегия"?
Советую почитать на эту тему.

http://ooad.asf.ru/patterns/

4.0K
01 апреля 2003 года
Dsanni
1 / / 01.04.2003
Green стукни в аську, ты тут как-то про Starteam, у меня большоя проблемма не могу историю удалить уже 30Gb засралось. Помоги если можеш.
2.0K
05 апреля 2003 года
segev
67 / / 19.01.2003
udgine
Наконец-то кто-то меня поддержал, я уж было засомневался.

Green
Спасибо за ссылочку. Почитал про "стратегию". Стандартное и довольно очевидное решение.
"Стратегия" обычно реализуется через наследование, хотя никто не запрещает использовать шаблоны. В этом случае контекст является собственно шаблоном, а класс-стратегия - его фактический параметр. Именно так, кстати, устроен стандартный класс string.
Как твой пример связан со стратегией я так и не понял.

Цитата:
это всё баг VC++6.0, в .NET 2003 все отлично работает!


В современных компиляторах очень много возможностей, которые не стоит использовать при правильном проектировании (ИМХО).

3
06 апреля 2003 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by segev
Спасибо за ссылочку. Почитал про "стратегию". Стандартное и довольно очевидное решение.
"Стратегия" обычно реализуется через наследование, хотя никто не запрещает использовать шаблоны. В этом случае контекст является собственно шаблоном, а класс-стратегия - его фактический параметр. Именно так, кстати, устроен стандартный класс string.
Как твой пример связан со стратегией я так и не понял.



Про использование шаблонов при реализации "стратегии" ты всё понял правильно. Честно говоря, не вижу преимуществ у наследования перед использованием шаблонов, т.к. в большинстве случаев придется использовать множественное наследование, что само по себе не есть хорощо. Почему, думаю, очевидно.

Мой пример связан со стратегией след. образом. Есть класс "документ", есть класс "вид", т.е. обычная концепция Doc/View. Способ заполнения вида и выбор информации из документа могут варироваться в различных проектных решениях. Т.о. целесообразно введение стратегии заполнения. При этом выбор иформации из документа производиться по индексу, передаваемому в стратегию, как праметр шаблона. Т.о. класс документа мог бы выглядеть примерно так:

class Human {
private:
int age;
int weight;
char* name;

public:
char* get(int index)
{
switch(i) {
case 0: return name;
case 1:
........
default:
........
}
}

};

Но в данном случае switch - это лишний код и лишние операции, т.к. ещё на этапе компиляции будет известно какие из его веток будут работать, а какие - никогда не будут пройдены.
Т.о. я решил "реализовать" этот switch еще на этапе компиляции при помощи шаблонных функций:

template<int T> char* get() // то же что и default
{
......
}

template<> char* get<0>() // то же что и case 0
{
return name;
}

template<> char* get<1>() // то же что и case 1
{
......
}

и т.д.

Т.о. код, который не используется, не будет присутствовать в скомпилированном объектном файле, и нет передачи аргументов при вызове функций.

Т.о. switch вроде бы есть, а вроде и нет.
Как видите, ни перегрузка ни использование нескольких функций с разными именами здесь не подходит.

Я не спрашиваю, будет ли это работать, хорошо ли делать так или нет. Я знаю, что это работает потому, что это уже работает. И этот подход вписывается в концепцию всего проекта и приводит к ощутимым положительным результатам как по гибкости проектирования, так и по быстродействию.
Первоначальный вопрос был про нежелание такого кода работать в VC++6.0, потом выяснилось, что это особенность компилятора, а не языка.

Цитата:
Originally posted by segev
В современных компиляторах очень много возможностей, которые не стоит использовать при правильном проектировании (ИМХО).



Звучит примерно так:
"Мы боимся всего нового, поэтому и Вам советуем действовать постаринке."

"Правильное проектирование" - весьма субъективное понятие.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог