Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.50/36: Рейтинг темы: голосов - 36, средняя оценка - 4.50
alsav22
5455 / 4850 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
1

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

22.09.2011, 05:22. Просмотров 6611. Ответов 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
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
22.09.2011, 05:22
Ответы с готовыми решениями:

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

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

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

Как правильно вписать функцию в h-файл и правильно её отразить в основной функции?
Создать внешнюю библиотеку, в которой написана функция вывода символьного массива обратном ...

Файл: Как наиболее эффективно разделить строку?
В файле есть например: James 0.8 0.7 0.75 0.5 0.85 J Как наиболее эффективно разделить эту...

5
kazak
3065 / 2386 / 255
Регистрация: 11.03.2009
Сообщений: 5,444
Завершенные тесты: 1
22.09.2011, 05:31 2
Для шаблонов определение и реализация должны быть в одном файле.
0
CAHTEXHUK
Заблокирован
22.09.2011, 05:44 3
когда компилятор видит шаблонную функцию он должен знать для каких аргументов его инстанцировать. То есть если у тебя определение шаблона и его вызов находятся в разных файлах(.Cxx), то ничего не получится, компилер не инстанцирует шаблон, а просто создаст ссылку на определение, которую должен разрешить компоновщик, но так как ничего не инстанцированно, то линкер в свою очередь лажает.

В учебной программе можешь не париться и писать всё в хидере, слишком сильно это время компиляции не увеличит, а для больших проектов существуют предкомпильные заголовки. Ещё как вариант можно явно инстанцировать всё что нужно в конце файла реализации и при этом следить, чтобы не проинтанцировать чтото дважды для одних и тех же параметров, иначе линкер опять обругается
0
alsav22
5455 / 4850 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
22.09.2011, 07:38  [ТС] 4
Я в этих определениях уже запутался: прототип, объявление, определение, реализация... Ты ещё добавил инстанцировать (инстанация?). Если я правильно понимаю, то это означает создать экземпляр функции по шаблону? Писать всё в хидере не годится. Вернее, годится, если файл исходного кода один, а если не один и во втором тоже вызывается шаблонная функция, то компоновщик выдаёт двойное определение: 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
CAHTEXHUK
Заблокирован
22.09.2011, 09:14 5
в итоге ты вернулся к модели включения. Никакого смысла так разделять файлы нет, только ещё больше всё запутал
1
alsav22
5455 / 4850 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
22.09.2011, 18:43  [ТС] 6
Согласен, что смысла нет. До настоящих смыслов я ещё не дошёл. Дошёл до главы "Раздельная компиляция". Там пишется:"...Таким образом, исходную программу можно разбить на три части:
- Заголовочный файл, содержащий объявления структур и прототипы функций, использующих эти структуры.
- Файл с исходным кодом, содержащий код функций, работающих со структурами.
- Файл с исходным кодом, содержащий код, осуществляющий вызовы этих функций...
Ещё:"...В заголовочных файлах обычно содержатся следующие элементы:
- Прототипы функций.
- Символьные константы, определённые с помощью директивы #define или const.
- Объявления структур.
- Объявления классов.
- Объявления шаблонов.
- Встроенные функции..."

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

Добавлено через 1 час 11 минут
Вроде бы разобрался. Получается так. Когда компилятор встречает в каком-либо файле исходного кода вызов шаблонной функции с некими аргументами, то он создаёт экземпляр этой функции под этот тип аргументов, а для этого, в этом файле должно присутствовать определение шаблона (получается, что у определения шаблона видимость в пределах файла). После этого, если компилятор встречает в другом файле исходного кода вызов шаблонной функции с таким же типом аргументов, то он использует ранее созданный экземпляр функции, и поэтому в этом файле ему уже не нужно определение шаблона (только прототип). Но что интересно, это не касается определения специализации шаблона. Она видна во всех файлах (внешнее связывание), и именно она давала ошибку двойного определения, если присутствовала в заголовочном файле и этот файл включался в несколько файлов исходного кода. Определение специализаци шаблона (так же как определения функций) нужно помещать в отдельный файл, а в заголовочном оставлять только прототипы и определения шаблонов. Тогда такой заголовочный файл можно включать в любое колличество файлов исходного кода.
1
22.09.2011, 18:43
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
22.09.2011, 18:43

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

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

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


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

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru