Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.79/29: Рейтинг темы: голосов - 29, средняя оценка - 4.79
8 / 8 / 2
Регистрация: 04.12.2012
Сообщений: 130
1

Шаблонные функции только для определённых типов!

20.01.2013, 12:20. Показов 5293. Ответов 18
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Как сделать чтобы для шаблонной функции генерировались только экземпляры для нескольких заданных типов, а остальные не генерировались?
Следующее определение не помогает (в конце кода):
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
template <typename str_type>
double strToDouble(str_type *in_add, const str_type decimal_separator='.');
 
template <typename str_type>
double strToDouble(str_type *in_add, const str_type decimal_separator) {
    auto_arr<str_type> str=cloneStr(in_add); // for sake able to modify
    str_type *int_pos(str), *fract_pos(0), *exp_pos(0);
    if((*str=='+')||(*str=='-')) str++;
    bool is_hex((str[0]=='0')&&(str[1]=='x'));
    while(*str!=0) {
        if((*str==decimal_separator)&&(fract_pos==0)) *str=0, fract_pos=++str;
        if(((*str=='e')||(*str=='E'))&&(exp_pos==0)) {
            if(is_hex&&((str[1]!='0')||(str[2]!='x'))) continue;
            *str=0; exp_pos=++str; break;
        }
    }
    // check here that the fractional, integer and exponential part not equal zero !!
    double out_number=strToInt(int_pos);
    if(fract_pos) {
        out_number;
    }
    if(exp_pos)
    return out_number;
}
 
template double strToDouble(char *in_add, const char decimal_separator);
template double strToDouble(wchar_t *in_add, const wchar_t decimal_separator);
проблема состоит в том что если вызвать функцию как:
C++
1
std::cout<<"strToDouble="<<strToDouble("k")<<std::endl;
то подставляется const char вместо str_type, а надо просто char, потому что тогда всё что внутри объявлено с типом str_type нельзя изменять что никоим образом мне не подходит! Помогает:
C++
1
std::cout<<"strToDouble="<<strToDouble<char>("k")<<std::endl;
но это не удобно постоянно писать тип при вызове функции, теряется весь смысл "template'ности" ))
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
20.01.2013, 12:20
Ответы с готовыми решениями:

Можно ли сделать шаблон функции только для определенных типов?
Например template&lt;typename T&gt; void func(T x){} Где T может быть только int,double и float

Template для определенных типов
Доброго времени суток, можно ли сделать template для определенных типов данных? К примеру:...

Шаблонные функции для обработки матриц
#include &lt;iostream&gt; #include &lt;cstdlib&gt; #include &lt;ctime&gt; template &lt;class T&gt; void...

Шаблонные функции для заполнения массива
Здравствуйте, уважаемое сообщество. Пожалуйста, помогите с решением задачи. Тема - шаблонные...

18
What a waste!
1608 / 1300 / 180
Регистрация: 21.04.2012
Сообщений: 2,729
20.01.2013, 12:31 2
Цитата Сообщение от popelyuk Посмотреть сообщение
о подставляется const char вместо str_type, а надо просто char
"k" - это строковый литерал, его символы костантны, поэтому и выводится const char, а не char. Почему бы просто не объявить in_add как str_type const*?
0
DU
1500 / 1146 / 165
Регистрация: 05.12.2011
Сообщений: 2,279
20.01.2013, 12:34 3
можно внутри попробовать заюзать удалятор константы.
что-нибубдь типа
typedef typename boost::remove_const<str_type>::type non_const_str_type;
и там, где надо менять переменную использовать non_const_str_type вместо str_type
в новом стандарте такая штука возможно уже в std
0
8 / 8 / 2
Регистрация: 04.12.2012
Сообщений: 130
20.01.2013, 12:51  [ТС] 4
Цитата Сообщение от DU Посмотреть сообщение
можно внутри попробовать заюзать удалятор константы.
что-нибубдь типа
typedef typename boost::remove_const<str_type>::type non_const_str_type;
и там, где надо менять переменную использовать non_const_str_type вместо str_type
в новом стандарте такая штука возможно уже в std
как не смешно, но есть решение проще, только что нашёл, такое смешное я просто в шоке, нужно для этого его объявить const str_type тогда в str_type подставляется только char из-за того, скорее всего, что если бы поставлялось const char, то было бы const const char - что есть ошибка!

Добавлено через 4 минуты
Ну а вообще тема остаётся открытой, как для template функции генерировать только определённые инстанации?? И запрещать генерировать остальные?
0
Эксперт С++
1674 / 1046 / 174
Регистрация: 27.09.2009
Сообщений: 1,945
20.01.2013, 13:44 5
Цитата Сообщение от popelyuk Посмотреть сообщение
как для template функции генерировать только определённые инстанации?? И запрещать генерировать остальные?
Объявить эту функцию, но не определять. Определить только конкретные специализации (не забываем, что для шаблонных функций запрещена частичная специализация, вместо неё используют перегрузки).
Пример:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 // В файле myprint.h
// Общая форма функции
template<typename T> void print(T value);
// Чтобы компилятор не пытался инстанциировать, пообещаем ему специализации
template<> void print<int>(int);
template<> void print<double>(double);
 
// В файле myprint.cpp
template<> void print<int>(int value)
{
    printf("%d", value);
}
 
template<> void print<double>(double value)
{
    printf("%f", value);
}
 
// в файле main.cpp
#include "myprint.h"
 
int main()
{
    const int a = 1;
    const double b = 2;
    print(a);
    print(b);
}
Добавлено через 9 минут
В C++11 есть такая вещь, как extern template, подавляющая неявную инстанциацию в надежде, что где-то есть явная.
0
8 / 8 / 2
Регистрация: 04.12.2012
Сообщений: 130
20.01.2013, 13:50  [ТС] 6
Цитата Сообщение от Nick Alte Посмотреть сообщение
Объявить эту функцию, но не определять. Определить только конкретные специализации (не забываем, что для шаблонных функций запрещена частичная специализация, вместо неё используют перегрузки).
Пример:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 // В файле myprint.h
// Общая форма функции
template<typename T> void print(T value);
// Чтобы компилятор не пытался инстанциировать, пообещаем ему специализации
template<> void print<int>(int);
template<> void print<double>(double);
 
// В файле myprint.cpp
template<> void print<int>(int value)
{
    printf("%d", value);
}
 
template<> void print<double>(double value)
{
    printf("%f", value);
}
 
// в файле main.cpp
#include "myprint.h"
 
int main()
{
    const int a = 1;
    const double b = 2;
    print(a);
    print(b);
}
Добавлено через 9 минут
В C++11 есть такая вещь, как extern template, подавляющая неявную инстанциацию в надежде, что где-то есть явная.
Всё это конечно хорошо, но опять же теряется смысл в объявлении как template, ведь это по сути ничем не отличается от объявления двух перегруженных не template функций и если что-то нужно будет изменить придется менять в обоих, смысл тогда заморачиваться с template'ми?
0
Каратель
Эксперт С++
6609 / 4028 / 401
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
20.01.2013, 13:53 7
Цитата Сообщение от popelyuk Посмотреть сообщение
проблема состоит в том что если вызвать функцию как:
C++
1
std::cout<<"strToDouble="<<strToDouble("k")<<std::endl;
то подставляется const char вместо str_type
в данном случае подставляется const char[2]
Цитата Сообщение от popelyuk Посмотреть сообщение
а надо просто char, потому что тогда всё что внутри объявлено с типом str_type нельзя изменять что никоим образом мне не подходит!
а что вы хотите изменить?
0
Эксперт С++
1674 / 1046 / 174
Регистрация: 27.09.2009
Сообщений: 1,945
20.01.2013, 14:06 8
Цитата Сообщение от popelyuk Посмотреть сообщение
ведь это по сути ничем не отличается от объявления двух перегруженных не template функций
Ну почему же, никто не мешает использовать явную инстанциацию:
C++
1
2
3
4
5
6
7
8
9
10
11
12
// В myprint.h
extern template<typename T> void print(T value);
 
// В myprint.cpp
 
template<typename T> void print(T value)
{
    cout << value;
}
 
template void print<int>(int);
template void print<double>(double);
0
8 / 8 / 2
Регистрация: 04.12.2012
Сообщений: 130
20.01.2013, 14:17  [ТС] 9
Цитата Сообщение от Jupiter Посмотреть сообщение
в данном случае подставляется const char[2]
ну насколько я знаю указатель не может быть 2 или 100 он просто указывает на первый элемент массива, ток что всё же const char
Цитата Сообщение от Jupiter Посмотреть сообщение
а что вы хотите изменить?
ну объявить например некоторое значении внутри template функции с типом str_type а потом изменить его:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
char *some_fun();
 
template <typename str_type>
int function(str_type *val);
//....
     str_type *some_val=some_fun();
     some_val[2]='k';// ошибка str_type=const char
 
}
 
int main () {
     function("const string");
     return 0;
}
Но, в общем, можете не парится я уже нашёл решение, выше написал.

Добавлено через 10 минут
Цитата Сообщение от Nick Alte Посмотреть сообщение
C++
1
2
template void print<int>(int);
template void print<double>(double);
в моём примере с const char и char это не работало вместо использования готовой специализации для char генерировалась для const char может быть с экстернами это по другому работает не знаю даже.
Цитата Сообщение от Nick Alte Посмотреть сообщение
C++
1
2
3
4
5
6
// В myprint.cpp
 
template<typename T> void print(T value)
{
    cout << value;
}
это что же теперь template implementation можно совать в .cpp файл по новым стандартам??
0
Эксперт С++
1674 / 1046 / 174
Регистрация: 27.09.2009
Сообщений: 1,945
20.01.2013, 14:25 10
Цитата Сообщение от popelyuk Посмотреть сообщение
это что же теперь template implementation можно совать в .cpp файл по новым стандартам??
Налицо явное непонимание. Цель была не дать пользователю создавать инстанциации самому. Для этого функцию объявляем, но не определяем. Все разрешённые инстанциации создаются в отдельном .cpp. Для этого в нём определяем шаблон нашей функции и создаём явные инстанциации для int и double. Это полноценные самостоятельные функции несмотря на то, что созданы из шаблона, поэтому они линкуются с вызовами, сделанными из других .cpp, где доступно только объявление.
0
576 / 559 / 47
Регистрация: 16.12.2011
Сообщений: 1,389
20.01.2013, 14:32 11
Цитата Сообщение от popelyuk Посмотреть сообщение
Как сделать чтобы для шаблонной функции генерировались только экземпляры для нескольких заданных типов, а остальные не генерировались?
Такая тема уже не раз поднималась. в новом стандарте так и не ввели средства для этого. Поэтому можно изгаляться по-разному. Например, сделать статик ассерт на все типы, кроме определенных.
0
8 / 8 / 2
Регистрация: 04.12.2012
Сообщений: 130
20.01.2013, 14:34  [ТС] 12
Цитата Сообщение от Nick Alte Посмотреть сообщение
Налицо явное непонимание. Цель была не дать пользователю создавать инстанциации самому. Для этого функцию объявляем, но не определяем. Все разрешённые инстанциации создаются в отдельном .cpp. Для этого в нём определяем шаблон нашей функции и создаём явные инстанциации для int и double. Это полноценные самостоятельные функции несмотря на то, что созданы из шаблона, поэтому они линкуются с вызовами, сделанными из других .cpp, где доступно только объявление.
Цель была не совсем такая, нужно объявить template функцию (один раз!), а потом как-то описать под какие типы её можно генерить, а под остальные чтобы она сама не генерировалсь, вот!
0
Эксперт С++
1674 / 1046 / 174
Регистрация: 27.09.2009
Сообщений: 1,945
20.01.2013, 14:41 13
Цитата Сообщение от popelyuk Посмотреть сообщение
Цель была не совсем такая, нужно объявить template функцию (один раз!), а потом как-то описать под какие типы её можно генерить, а под остальные чтобы она сама не генерировалсь, вот!
Это то же самое абсолютно. Способ решения я и привёл: описываем функцию и инстанциируем её для всех нужных типов в отдельной единице трансляции. Эти инстанциации доступны для линкера, а создать новые инстанциации в других модулях невозможно, потому что определение шаблона функции этим модулять не доступно, у них есть только объявление. Заметим: во втором примере функция описана один раз, а инстанциируется два раза, для двух разрешённых типов.

Добавлено через 2 минуты
Видимо, источник взаимного непонимания - как раз явная инстанциация.
Конструкция
C++
1
template void print<int>(int);
- не объявление функции, а приказ её явно инстанциировать из шаблона для типа int. Объявление выглядело бы как
C++
1
template <> void print<int>(int);
0
8 / 8 / 2
Регистрация: 04.12.2012
Сообщений: 130
20.01.2013, 15:13  [ТС] 14
У меня на это матерится:
C++
1
extern template <typename T> void print(T value);
Говорит что:
D:\Dropbox\source\test\test.h:2: error: expected unqualified-id before '<' token
0
Эксперт С++
1674 / 1046 / 174
Регистрация: 27.09.2009
Сообщений: 1,945
20.01.2013, 15:43 15
Так то ж из C++11. Попробуй без слова extern.
0
8 / 8 / 2
Регистрация: 04.12.2012
Сообщений: 130
20.01.2013, 16:02  [ТС] 16
Цитата Сообщение от Nick Alte Посмотреть сообщение
Так то ж из C++11. Попробуй без слова extern.
да, теперь всё компилируется, но наверно я всё же чего-то не понимаю, а самое главное не понимаю чего именно я не понимаю! Я просто думал что определения темплейт функций должны быть всегда в хедерах и никогда в .cpp файлах, иначе что-то будет, а что будет? Подскажите ,пожалуйста, что мне прочитать чтобы "получить просветление" так сказать???

Добавлено через 1 минуту
только не советуйте "курить стандарт", как мне где-то тут или не тут советовали, чего-то не очень длинное желательно
0
DU
1500 / 1146 / 165
Регистрация: 05.12.2011
Сообщений: 2,279
20.01.2013, 16:05 17
вот на мой взгляд одна из лучших книг по шаблонам в плюсах:
http://www.ozon.ru/context/detail/id/3960662/
хоть и до новостандартная, все равно очень хорошая.
в ней есть в частности глава 10 про инстанцирование.
1
Эксперт С++
1674 / 1046 / 174
Регистрация: 27.09.2009
Сообщений: 1,945
20.01.2013, 16:46 18
Цитата Сообщение от popelyuk Посмотреть сообщение
Я просто думал что определения темплейт функций должны быть всегда в хедерах и никогда в .cpp файлах, иначе что-то будет, а что будет?
Это не религиозная догма. Содержимое шаблонов быть в заголовках, чтобы их можно было инстанциировать: для этого ведь необходимо знать содержимое шаблона. Ведь что такое инстанциация? Берём шаблон void printf<T>(T) (который сам по себе не функция, а только заготовка для создания функций), подставляем туда конкретные типы (ну или константы) и на выходе получаем конкретный тип или конкретную функцию: void print<int>(int). А потом - другую функцию, формально совершенно независимую от первой: void print<double>(double).

То есть, мы выносим определение шаблона в отдельный файл и там же инстанциируем всё, что нам нужно. В результате этот файл по сути содержит набор уже окончательных функций. Обращение к таким функциям происходит как и к любым другим, через механизм связывания (через линкер). Для обращения к функции надо лишь знать типы аргументов и возвращаемого значения: объявление этой функции.

Так что при определении шаблонов внутри .cpp это "иначе что-то будет" сводится к невозможности инстанциировать шаблоны вне тех .cpp, в которых они объявлены. Что обычно противоречит нашим намерениям, но в данном случае - именно то, что доктор прописал.
1
8 / 8 / 2
Регистрация: 04.12.2012
Сообщений: 130
20.01.2013, 16:51  [ТС] 19
Цитата Сообщение от Nick Alte Посмотреть сообщение
Это не религиозная догма. Содержимое шаблонов быть в заголовках, чтобы их можно было инстанциировать: для этого ведь необходимо знать содержимое шаблона. Ведь что такое инстанциация? Берём шаблон void printf<T>(T) (который сам по себе не функция, а только заготовка для создания функций), подставляем туда конкретные типы (ну или константы) и на выходе получаем конкретный тип или конкретную функцию: void print<int>(int). А потом - другую функцию, формально совершенно независимую от первой: void print<double>(double).

То есть, мы выносим определение шаблона в отдельный файл и там же инстанциируем всё, что нам нужно. В результате этот файл по сути содержит набор уже окончательных функций. Обращение к таким функциям происходит как и к любым другим, через механизм связывания (через линкер). Для обращения к функции надо лишь знать типы аргументов и возвращаемого значения: объявление этой функции.

Так что при определении шаблонов внутри .cpp это "иначе что-то будет" сводится к невозможности инстанциировать шаблоны вне тех .cpp, в которых они объявлены. Что обычно противоречит нашим намерениям, но в данном случае - именно то, что доктор прописал.
теперь всё понятно, спасибо за уделённое время!
0
20.01.2013, 16:51
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
20.01.2013, 16:51
Помогаю со студенческими работами здесь

Шаблонные классы. Присвоение к указателю и приведение типов
Добрый вечер, ув. форум, есть к вам вопрос. Есть род. абстрактный класс: ParentAbstact Есть два...

Преобразование типов для копирования определенных ячеек из одного столбца в массив
Доброго времени суток. Есть таблица в экселе. Цель - скопировать определенные ячейки из одного...

Шаблонные функции для нахождения минимального и максимального элемента пары чисел
Описать функции-шаблоны для нахождения минимального и максимального элемента пары чисел. Задано...

Написать шаблонные, перегруженные функции для ввода и вывода на экран массивов и матриц
Добрый вечер всем! Помогите написать написать шаблонные, перегруженные функции input и output для...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
19
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru