Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.82/49: Рейтинг темы: голосов - 49, средняя оценка - 4.82
5499 / 4894 / 831
Регистрация: 04.06.2011
Сообщений: 13,587

Как правильно разделить файл в шаблонами?

22.09.2011, 05:22. Показов 9393. Ответов 5
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Попробовал разделить один файл на два. В заголовочный "proba.h" поместил прототип шаблона и специализацию. В одном файле исходного кода оставил функцию main(), а во второй поместил определения шаблона и специализации.

Заголовочный файл "proba.h":
C++
1
2
3
template <class T>
T max5(T m[], int x);
template <> const char* max5(const char* m[], int x);
Первый файл:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;
#include "proba.h"
 
int main()
{
     int t[6] = {777, 34, 34, 66, 777, 1234};
         int l = max5(t, 6);
         cout << l << endl;
 
    double t2[4] = {7.98, 7.90, 3.676, 6.56};
    double l2 = max5(t2, 4);
        cout << l2 << endl;
        
        const char* uk[4] = {"sd","987654321", "qwertyu", "123456789"};
        const char* n = max5(uk, 4);
        cout << &n << "  " << n <<  endl;
        
        system ("pause");
    return 0;
}
Второй файл:
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
#include <iostream>
using namespace std;
#include "proba.h"
 
template <> const char* max5<const char*>( const char* m[], int x)
{
    int n = 0;
        unsigned int p = strlen (m[0]);
        for (int i = 1; i < x; i++)
        if (p < strlen (m[i]))
        {
                p = strlen (m[i]);
                n = i;
        }
 
        return m[n];
}       
 template <class T>
 T max5(T m[], int x)
{
        T p = m[0];
        for (int i = 1; i < x; i++)
        { 
                if (p < m[i]) p = m[i];
        }               
        return p;       
}
При постоении выдаёт ошибки:
1>------ Построение начато: проект: 8-1, Конфигурация: Debug Win32 ------
1> 8-1.cpp
1> Создание кода...
1> Компиляция...
1> 8-2.cpp
1> Создание кода...
1>8-1.obj : error LNK2019: ссылка на неразрешенный внешний символ "double __cdecl max5<double>(double * const,int)" (??$max5@N@@YANQANH@Z) в функции _main
1>8-1.obj : error LNK2019: ссылка на неразрешенный внешний символ "int __cdecl max5<int>(int * const,int)" (??$max5@H@@YAHQAHH@Z) в функции _main
1>D:\MY C++Projects\8-4-5\Debug\8-1.exe : fatal error LNK1120: 2 неразрешенных внешних элементов
========== Построение: успешно: 0, с ошибками: 1, без изменений: 0, пропущено: 0 ==========

Если же определене шаблона и специализации тоже записать в заголовочный файл, а не во второй файл исходного кода, то всё проходит нормально. Но если создать второй файл исходного кода (с этим заголовочным файлом) и в нём использовать шаблон, то компоновщик выдаёт ошибку:fatal error LNK1169: обнаружен многократно определенный символ - один или более.
Это из за того, что определения шаблона и специализации присутствуют (через заголовочный файл) и в первом файле и во втором. Как правильно это всё делается? С функциями получается, а с шаблонами непонятно как правильно делать.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
22.09.2011, 05:22
Ответы с готовыми решениями:

Как правильно разделить файл исходного кода?
Имеем работающий код на ВС++ 6 (более 10 тысяч строк) в одном *.cpp Нужно разделить его на несколько файлов. Конкретнее: ...

Rак правильно подключать файлы с шаблонами
Доброго времени суток! Есть код: main.cpp #include &lt;iostream&gt; #include &lt;string&gt; #include &quot;cls.h&quot; using std::string; ...

Как правильно разделить жесткий диск?
1. Как создать два первичный раздела на жестком диске. Че то никак не могу разобраться? 2. А вообще передо мной стоит задача...

5
 Аватар для kazak
3599 / 2741 / 354
Регистрация: 11.03.2009
Сообщений: 6,298
22.09.2011, 05:31
Для шаблонов определение и реализация должны быть в одном файле.
0
Заблокирован
22.09.2011, 05:44
когда компилятор видит шаблонную функцию он должен знать для каких аргументов его инстанцировать. То есть если у тебя определение шаблона и его вызов находятся в разных файлах(.Cxx), то ничего не получится, компилер не инстанцирует шаблон, а просто создаст ссылку на определение, которую должен разрешить компоновщик, но так как ничего не инстанцированно, то линкер в свою очередь лажает.

В учебной программе можешь не париться и писать всё в хидере, слишком сильно это время компиляции не увеличит, а для больших проектов существуют предкомпильные заголовки. Ещё как вариант можно явно инстанцировать всё что нужно в конце файла реализации и при этом следить, чтобы не проинтанцировать чтото дважды для одних и тех же параметров, иначе линкер опять обругается
0
5499 / 4894 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
22.09.2011, 07:38  [ТС]
Я в этих определениях уже запутался: прототип, объявление, определение, реализация... Ты ещё добавил инстанцировать (инстанация?). Если я правильно понимаю, то это означает создать экземпляр функции по шаблону? Писать всё в хидере не годится. Вернее, годится, если файл исходного кода один, а если не один и во втором тоже вызывается шаблонная функция, то компоновщик выдаёт двойное определение: fatal error LNK1169: обнаружен многократно определенный символ - один или более. Получается так, что если имеется несколько файлов исходного кода, в которых есть вызов шаблонной функции, то прототип шаблона должен присутствовать в каждом файле, а реализация шаблона только в одном. У меня так получилось: в одном заголовочном файле прототип шаблона и специализации, в другом заголовочном - реализация шаблона и специализации. Заголовочный с прототипами подключается к каждому файлу исходного кода (где есть вызоа шаблонной функции), а заголовочный с реализациями шаблона и специализации, только к первому файлу исходного кода.

Первый заголовочный "proba.h":
C++
1
2
3
4
5
6
7
8
#ifndef PROBA_H
#define PROBA_H
template <class T>
T max5(T m[], int x);
template <> const char* max5(const char* m[], int x);
void fun3();
void fun4();
#endif
Второй заголовочный "proba2.h":
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
#ifndef PROBA_H_2
#define PROBA_H_2
template <class T>
T max5(T m[], int x)
{
    T p = m[0];
    for (int i = 1; i < x; i++)
    { 
        if (p < m[i]) p = m[i];
    }       
    return p;   
}
template <> const char* max5( const char* m[], int x)
{
    int n = 0;
    unsigned int p = strlen (m[0]);
    for (int i = 1; i < x; i++)
    if (p < strlen (m[i]))
    {
        p = strlen (m[i]);
        n = i;
    }
 
    return m[n];
}
#endif
Первый файл исходного кода:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;
#include "proba.h"
#include "proba2.h"
 
int main()
{
     int t[6] = {777, 34, 34, 66, 777, 1234};
         int l = max5(t, 6);
         cout << l << endl;
 
    double t2[4] = {7.98, 7.90, 3.676, 6.56};
    double l2 = max5(t2, 4);
        cout << l2 << endl;
        
        const char* uk[4] = {"sd","987654321", "qwertyu", "123456789"};
        const char* n = max5(uk, 4);
        cout  << n <<  endl;
        fun3();
        system ("pause");
    return 0;
}
Второй файл исходного кода:
C++
1
2
3
4
5
6
7
8
9
10
#include <iostream>
using namespace std;
#include "proba.h"
 
void fun3()
{
    int f2[3] = {12, -45, -2};
    int j1 = max5(f2, 3);
    cout << j1 << endl;
}
Третий файл исходного кода:
C++
1
2
3
4
5
6
7
8
9
10
#include <iostream>
using namespace std;
#include "proba.h"
 
void fun4()
{
    const char* uk[3] = {"sd","9876", "qwerty"};
    const char* n = max5(uk, 3);
    cout << n <<  endl;
}
При таком подходе всё нормально компонуется.
0
Заблокирован
22.09.2011, 09:14
в итоге ты вернулся к модели включения. Никакого смысла так разделять файлы нет, только ещё больше всё запутал
1
5499 / 4894 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
22.09.2011, 18:43  [ТС]
Согласен, что смысла нет. До настоящих смыслов я ещё не дошёл. Дошёл до главы "Раздельная компиляция". Там пишется:"...Таким образом, исходную программу можно разбить на три части:
- Заголовочный файл, содержащий объявления структур и прототипы функций, использующих эти структуры.
- Файл с исходным кодом, содержащий код функций, работающих со структурами.
- Файл с исходным кодом, содержащий код, осуществляющий вызовы этих функций...
Ещё:"...В заголовочных файлах обычно содержатся следующие элементы:
- Прототипы функций.
- Символьные константы, определённые с помощью директивы #define или const.
- Объявления структур.
- Объявления классов.
- Объявления шаблонов.
- Встроенные функции..."

Стал пробовать. С функциями, структурами всё получилось, а с шаблонами нет. Разделил прототип шаблона и определение его (как с функциями делал) не получается. Вот и возник вопрос. Написано, что в заголовочном следует разместить объявление шаблона. Под этим, скорее всего, подразумевается прототип шаблона вместе с определением.

Добавлено через 1 час 11 минут
Вроде бы разобрался. Получается так. Когда компилятор встречает в каком-либо файле исходного кода вызов шаблонной функции с некими аргументами, то он создаёт экземпляр этой функции под этот тип аргументов, а для этого, в этом файле должно присутствовать определение шаблона (получается, что у определения шаблона видимость в пределах файла). После этого, если компилятор встречает в другом файле исходного кода вызов шаблонной функции с таким же типом аргументов, то он использует ранее созданный экземпляр функции, и поэтому в этом файле ему уже не нужно определение шаблона (только прототип). Но что интересно, это не касается определения специализации шаблона. Она видна во всех файлах (внешнее связывание), и именно она давала ошибку двойного определения, если присутствовала в заголовочном файле и этот файл включался в несколько файлов исходного кода. Определение специализаци шаблона (так же как определения функций) нужно помещать в отдельный файл, а в заголовочном оставлять только прототипы и определения шаблонов. Тогда такой заголовочный файл можно включать в любое колличество файлов исходного кода.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
22.09.2011, 18:43
Помогаю со студенческими работами здесь

Как правильно разделить заданный массив
Всем доброго времени суток. У меня такой вопрос. У меня есть массив: . Как сделать так, чтобы можно было разделить массив на 2 части, чтобы...

Как правильно разделить программу на функции?
Как правильно разделить программу на функции? Подскажите, пожалуйста #include &quot;pch.h&quot; #include &lt;iostream&gt; using...

Как правильно разделить код по функциям
Проект VBA SCCESS 2003 Я построил код следующим образом: Private Sub Start_Click() For i = 0 to ii ' ii - количество записей в...

Как правильно разделить код по функциям
Проект VBA ACCESS 2003 Я построил код следующим образом: Private Sub Start_Click() For i = 0 to ii ' ii - количество записей в...

Как правильно разделить два числа
Подскажите пожалуйста, как правильно разделить два числа на ассемблере(TASM)! Возник спор с преподавателем! У меня есть два числа, оба...


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

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru