Как организовать функции-шаблоны и функции в заголовках и исходных файлах

Я учусь использовать функции шаблонов и организовывать свой код в несколько файлов. Я просмотрел Почему шаблоны могут быть реализованы только в заголовке file?, где они указывают, что я должен реализовать свои функции-шаблоны в заголовке; Я также посмотрел на встроенные функции C ++: объявить как таковое, определить как таковое или и то, и другое? Почему?, чтобы я знал, что мне следует определять полностью специализированные функции как встроенные в заголовок; и я посмотрел Зачем использовать файл «tpp» при реализации шаблонных функций и классов, определенных в заголовке?, где они предлагают определить шаблоны (а также полностью специализированные шаблоны?) в отдельном my.tpp и добавить #include "my.tpp" в конец моего заголовка.

Теперь мой вопрос как новичка: как мне совместить все это с обычными функциями.

Представьте себе следующее:

#ifndef IVAL_H
#define IVAL_H

//Function to determine if input string is of a given type
template<typename T>
bool is_type(std::string);

//Specialization when testing integer
//As I also want to accept  e.g. 4.0000 as an integer
template<>
bool is_type<int>(std::string);

//Function to get a given type
template<typename T>
T get_type(std::string);

//Finally a normal function to ask for [y/n]
bool yesNo(std::string prompt);

//Include templates definitions
#include"ival.tpp"

#endif /*IVAL_H*/

Затем, как было предложено в приведенных выше вопросах:

//in ival.tpp
#ifndef IVAL_TPP
#define IVAL_TPP

template<typename T>
bool is_type(std::string input)
{
//How to validate input
}

template<>
bool inline is_type<int>(std::string input)
{
\\How to validate when integer
}

template<typename T>
T get_type(std::string prompt)
{
//How to keep asking until valid input
//Using is_type
}
#endif /*IVAL_H*/

И, наконец, как .cpp моя обычная функция:

//in ival.cpp
#include "ival.h"

bool yesNo(std::string prompt)
{
//How to ask for [y/n]
//Using get_type<char>
}

Это вызывает некоторую путаницу в том, как правильно организовать мои функции. Когда в заголовке есть как функции шаблона, так и обычные функции, нормально ли делать то, что я сделал выше? (другой исходный файл для обычных функций) - это полностью специализированные функции, рассматриваемые как шаблон (т.е. определенные встроенными в файл, где находятся все шаблоны) или как функция (т.е. определенные только в .cpp, как и все другие функции).

Мне было удобнее определять функции шаблона в .cpp и явно создавать экземпляры в char, int, double, float и std::string


person Daniel Duque    schedule 11.02.2019    source источник
comment
Не существует идеального способа справиться с этим, и ваше решение кажется прекрасным.   -  person François Andrieux    schedule 11.02.2019
comment
Определения / тела шаблонных функций в заголовках, обычные определения / тела функций в файлах кода не только обычны, но и необходимы. Пожалуйста, объясните подробнее, что непонятно.   -  person Yunnosch    schedule 11.02.2019
comment
Если вы полностью специализируете шаблон функции, у вас остается обычная функция, определение которой находится в исходном файле.   -  person François Andrieux    schedule 11.02.2019
comment
@ FrançoisAndrieux В чем разница между этим и тем, что он встроен в заголовок с остальными шаблонами? Почему одно удобнее другого?   -  person Daniel Duque    schedule 11.02.2019
comment
@DanielDuque Все, что вы помещаете в заголовок, если вы когда-либо его измените, вам нужно будет перекомпилировать все, что #include в этом заголовке, или что включает файл, который включает этот заголовок, и т. Д. Если вы измените что-то в исходном файле (файл no другой файл должен включать), тогда вам нужно только перекомпилировать этот один файл и заново связать все. Поместите как можно больше в исходные файлы, чтобы ограничить время компиляции. Изменить: некоторым компиляторам может быть сложно оптимизировать исходные файлы, хотя другие могут утверждать, что встроенные функции (в заголовках) лучше для оптимизации (я не согласен).   -  person François Andrieux    schedule 11.02.2019
comment
FYI - ключевое слово inline не является обязательным, и, таким образом, компиляторы могут использовать встроенную подстановку для любой функции, которая не помечена как встроенная, и могут свободно генерировать вызовы функций для любой функции, отмеченной встроенной. Это меняет ваш вопрос?   -  person 2785528    schedule 11.02.2019


Ответы (1)


Мне ваше решение нравится. Обычно вы можете вставить код файла ival.tpp в конец файла ival.h и получить только один файл заголовка.

Как мне все это совместить с обычными функциями.

Обычные правила:

  • Поместите в файл * .cpp только определения ваших обычных функций.
  • Поместите все определения функций вашего шаблона, определения встроенных функций и объявления обычных функций в ваш файл * .h (или некоторые любят называть его * .hpp). Выберите порядок, чтобы большинство функций использовали / вызывали только те функции, которые определены над ними.
  • Только в случае необходимости (например, циклические зависимости): поместите достаточно шаблонов и встроенных функций объявлений в самый верх файла *.h, чтобы все вызываемые функции были объявлены до их вызова. Обычно это необходимо только в экзотических случаях.

Когда в заголовке есть как функции шаблона, так и обычные функции, нормально ли делать то, что я сделал выше?

Часто нет необходимости явно объявлять функции шаблона перед их определением, поэтому это часто опускается. Обычно это делается только в тех немногих случаях, когда это необходимо, например, когда функции шаблона ссылаются / вызывают друг друга. В графе вызовов могут быть даже циклы. Просто объявите все это встроенным и оставьте на усмотрение компилятора, что он на самом деле встраивает.

рассматриваются ли полностью специализированные функции как шаблон или как функция?

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

Было ли то, что я сделал более удобным, по сравнению с определением шаблонных функций в .cpp и явным экземпляром для char, int, double, float и std :: string?

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

person Johannes Overmann    schedule 11.02.2019