如何在标头和源文件中组织模板功能和功能

时间:2019-02-11 16:21:12

标签: c++ function code-organization function-templates

我正在学习使用模板功能,并在多个文件中组织代码。我看着Why can templates only be implemented in the header file?,他们指出我应该在标头中实现我的模板函数;我还查看了C++ inline functions: declare as such, define as such, or both? Why?,所以知道应该在标头中将完全专用的函数定义为内联;我看着Why use a “tpp” file when implementing templated functions and classes defined in a header?,他们建议在单独的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, floatstd::string

上,我所做的更为方便。

1 个答案:

答案 0 :(得分:0)

您的解决方案对我来说很好。通常,您可以在ival.h文件的末尾插入ival.tpp文件的代码,因此只有一个头文件。

  

如何将所有这些与常规功能结合在一起。

通常的规则是:

  • 仅将常规函数的定义放入* .cpp文件中。
  • 将所有模板函数定义,内联函数定义和常规函数声明放在* .h文件(或某些喜欢称为* .hpp的文件)中。选择一个顺序,以便大多数功能仅使用上面定义的/调用功能。
  • 仅在必要时(例如循环依赖性):在*.h文件的最上方放置足够的模板和内联函数声明,以便在调用所有被调用函数之前先对其进行声明。通常只有在特殊情况下才需要这样做。
  

在标头中同时具有模板功能和常规功能时,做上面的事情是正常的吗?

通常不需要在定义模板函数之前显式声明它们,因此通常将其省略。通常仅在少数情况下才需要这样做,即当模板函数相互引用/调用时。调用图中甚至可能存在周期。只需内联声明所有内容,然后将其实际内联的内容留给编译器即可。

  

将完全专用的功能视为模板还是功能?

将它们作为模板进行处理。所有可以看到通用模板定义的代码也应该可以看到专业化。否则,事情会变得混乱(程序的不同部分对相同的函数使用不同的代码)。

  

在.cpp中定义模板函数并将其显式实例化为char,int,double,float和std :: string时,我做起来是否更方便?

不。除非有具体理由,否则不要使用显式模板实例化。不要仅使用显式模板实例化来保持头文件的精简。