0

I was looking for a way to separate declaration and implementation in a template class (our professor bitches about this a lot) and I managed to find what looks to be a solution, here's the code (it also includes separation for single functions btw):

Template.h:

#pragma once

template <typename T>
void foo(T arg);


template <typename T> class test {
    T data;

public:
    test(T arg);

    T getData();
};

#include "Template.ipp"

Template.ipp:

#include "Template.h"
#include <iostream>

template <typename T>
void foo(T arg) {
    arg = arg + 1;
    std::cout << arg << std::endl;
}

template <typename T>
test<T>::test(T arg) : data(arg) {}

template <typename T>
T test<T>::getData() {
    return data;
}

main.cpp:

#include "Template.h"
#include "Template.h" // limit testing to see if #pragma once in Template.ipp is necessary
#include <iostream>


int main() {
    int xd = 3;
    foo(xd);
    std::cout << xd << std::endl;
    char xdd = 'a';
    foo(xdd);
    std::cout << xdd << std::endl;

    test<int> testxd(xd);
    std::cout << testxd.getData() << std::endl;

    test<char> testxdd(xdd);
    std::cout << testxdd.getData() << std::endl;
}

The code does compile in Visual Studio and the output is as expected

Output:

4
3
b
a
3
a

My question is: does the mutual inclusion risk to bite me in the ass if I use it in a bigger project? Is there any obvious downside to this approach? I know that putting the definition in the header is the standard practice so if I had a choice I'd rather go for it Also, is there a convention on the naming of the file? I used .ipp but I see that there's also .tpp, is there a difference in how they're used or are they used interchangeably?

P.S. this is my first question, please don't blast me too much

273K
  • 29,503
  • 10
  • 41
  • 64
Phoe87
  • 9
  • 2
  • It's working and sometimes done by other developers. If it's good is an opinion. BTW such and alternative is mentioned there https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file – 273K Jul 21 '23 at 00:22
  • 1
    As a minor nitpick, `#pragma once` is non-standard, so you might want to go with the good old `#ifndef MYTEMPLATE_H`, `#define MYTEMPLATE_H` guards instead. Either way will work in practice on 99% of compilers, though. – Jeremy Friesner Jul 21 '23 at 00:23
  • Why do you want the `#include "Template.h"` at all? – Davis Herring Jul 21 '23 at 00:28
  • @273K I did see that post but doing exactly as they said gave me a compilation error because the ipp file needs to include the header file and the circularity is the part that confuses me as I try to avoid them, the alternative, if I read that right and I think I did, looks like it misses the point of templates, btw, thanks a bunch for the early response, can I ask you to elaborate on what you mean by "If it's good is an opinion"? Do you mean it in a matter-of-factly way or is there actually some controversy on the use of techniques as such? – Phoe87 Jul 21 '23 at 00:39
  • @DavisHerring I was under the impression that I needed it to compile, I thought I had tested it but apparently I hadn't, sorry, what should I do? Is the practice on the site to delete the question? – Phoe87 Jul 21 '23 at 00:41
  • Think like a compiler time. When the compiler (preprocessor, really) sees a `#include` directive it replaces the directive with the contents of the named file and then continues parsing the now-larger file. Knowing this, you can work through what the compiler sees in your head and come up with something that looks like https://godbolt.org/z/zGTss14xT Anyway, from this you can see that the include of Template.h in Template.ipp is unnecessary. – user4581301 Jul 21 '23 at 00:50
  • Side note: Even if the `#pragma once` or traditional [include guard](https://en.wikipedia.org/wiki/Include_guard) isn't needed now, it's in your best interests to have one anyway for future proofing. They make so many problems go away that you should always have them out of general principles. I've never seen a case where they are detrimental and if you find one, you're either doing something wrong or solving a very interesting problem. – user4581301 Jul 21 '23 at 00:55
  • Your professor apparently does not understand C++. – Sam Varshavchik Jul 21 '23 at 00:58
  • *because the ipp file needs to include the header file* You seem to add .ipp to compilation units (source files), you did it improperly and would get ODR violations if you add more .cpp files with `#include "Template.h"`. – 273K Jul 21 '23 at 01:01
  • Personally (i.e. this is opinion) I wouldn't `#include "Template.h"` in the `Template.ipp` at all. By default - with most compilers and build environments or build scripts - `Template.ipp` will not be compiled separately, and there is no net benefit in a developer jumping through hoops to force it to compile. Similarly, no other source or header file (other than `Template.h`) will need to `#include "template.ipp"` directly either. Code that needs to *use* (or even just instantiate) the templates only needs to `#include "Template.h"`. – Peter Jul 21 '23 at 01:26
  • "our professor bitches about this a lot" - in general don't worry about nit picks by a professor. If they take points, then do it for that class, but otherwise assume your professor is good at math and writing papers and not at programming. – xaxxon Jul 24 '23 at 02:21

1 Answers1

0

It is a relatively common practice to put definitions of inline and templated functions in a separate file included at the end of the header file containing their declarations, sometimes with a .inl name. This is purely for source code organization, perhaps because the authors of a library intend for their “clean” header files to serve as documentation of the interface.

The #include in the other direction is never needed: the implementation file is still logically part of the header and thus is not compiled alone. (It wouldn’t be useful anyway since it wouldn’t instantiate any of the templates it’s defining.)

Davis Herring
  • 36,443
  • 4
  • 48
  • 76