2

I am learning to use template functions and organize my code in multiple files. I looked at Why can templates only be implemented in the header file? where they point out I should implement my template-functions in the header; I also looked at C++ inline functions: declare as such, define as such, or both? Why? so I know I should define fully specialized functions as inline in the header; and I looked at Why use a “tpp” file when implementing templated functions and classes defined in a header? where they suggest to define the templates (and also the fully specialized templates?) in a separate my.tpp and add #include "my.tpp" at the end of my header.

Now my question as a completely beginner is: How do I combine all this with regular functions.

Imagine the following:

#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*/

Then I have, as suggested in the questions quoted above:

//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*/

And finaly as a .cpp my normal function:

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

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

This causes some confusion as to how is the correct way of organizing my functions. When in a header we have both template functions and normal functions, is the normal thing to do what I did above? (different source file for normal functions), are the fully specialized functions treated as a template (i.e. defined inline in the file where all templates are) or as a function (i.e. defined just in .cpp as all other functions).

Is what I did more convenient over defining the template functions in .cpp and explicit instantiate to char, int, double, float, and std::string

Daniel Duque
  • 159
  • 9
  • There is no perfect way of dealing with this and your solution seems fine. – François Andrieux Feb 11 '19 at 16:23
  • Template function definitions/bodies in headers, normal function definition/bodies in code files is not only usual but necessary. Please explain more about what is unclear. – Yunnosch Feb 11 '19 at 16:23
  • If you fully specialize a function template you are left with a regular function whose's definition goes in a source file. – François Andrieux Feb 11 '19 at 16:23
  • @FrançoisAndrieux What is the difference between that and having it as inline in a header with the rest of templates? Why is one more convenient than another? – Daniel Duque Feb 11 '19 at 16:27
  • 1
    @DanielDuque Anything you put in a header, if you ever change it, you will need to recompile everything that `#include`'s that header, or that includes a file that includes that header, etc. If you change something in a source file (a file no other file should include) then you only need to recompile that one file and relink everything. Put as much as you can in source files to limit compilation time. Edit : Some compilers might have a hard time optimizing between source files though so others might argue that inline functions (in headers) are better for optimizations (I disagree). – François Andrieux Feb 11 '19 at 16:30
  • FYI - "the keyword inline is non-binding," and thus "compilers are free to use inline substitution for any function that's not marked inline, and are free to generate function calls to any function marked inline." Does this change your question? – 2785528 Feb 11 '19 at 17:58

1 Answers1

1

Your solution looks good to me. You can usually insert the code of file ival.tpp at the end of file ival.h and so have just one header file.

How do I combine all this with regular functions.

The usual rules are:

  • Put just the definitions of your regular functions into the *.cpp file.
  • Put all your template function definitions, inline function definitions and regular function declarations in your *.h file (or some like to call it *.hpp). Choose an order so that most function only use/call function which are defined above them.
  • Only if necessary (e.g. cyclical dependencies): Put just enough template and inline function declarations on the very top of the *.h file so that all called functions are declared before they are called. This is usually only necessary in exotic cases.

When in a header we have both template functions and normal functions, is the normal thing to do what I did above?

It is often not necessary to explicitly declare template functions before their definition, so this is often omitted. This is usually only done for the few cases where this is necessary, i.e. when the template function reference/call each other. There can even be cycles in the call graph. Just declare it all inline and leave it up to the compiler what it actually inlines.

are the fully specialized functions treated as a template or as a function?

Treat them as a template. All code which can see the definition of the generic template should also be able to see the specialization. Otherwise things get messy (different parts of you program use different code for the same function called).

Is what I did more convenient over defining the template functions in .cpp and explicit instantiate to char, int, double, float, and std::string?

No. Do not use explicit template instantiation unless you have a concrete reason to do so. Do not use explicit template instantiation just to keep your header files lean.

Johannes Overmann
  • 4,914
  • 22
  • 38