0

How is it that this works? Might be doing something wrong here.

def.H

enum some_enum { FAKE = 0, };

template < some_enum T> struct example_trait;

trait_implementation.H

#include "def.H"

template<> struct example_trait<FAKE> {  
static constexpr size_t member_var = 3;  };

generic_alg.H

#include "def.H"
template < some_enum T, typename TT = example_trait<T> > void
function() { std::cout << TT::member_var << std::endl; }

main.C

I can run this in my main as long as I include the headers in this order

  1. #include trait_implementation.H
    
  2. #include generic_alg.H
    

int main() {
    function<FAKE>();
    return 0; 
}

How is it that this compiles? can generic_alg.H compiles with only a forward declared traits class. It can see the traits definition when included in the right order, even though generic_alg.H itself does not include the trait_implementation.H. How is that plausible?

Using an online compiler I can only re-create: https://onlinegdb.com/B1BEUlp7E

Andre Marin
  • 540
  • 1
  • 6
  • 16
  • Header files don't get compiled. They just get copied and pasted into the source file where the `#include` line is. As long as you copy and paste in the right order, things will work. – NathanOliver Jan 28 '19 at 21:08
  • First of all there's only one translation unit here, which is main.cpp and includes everything else, no header is compiled on its own. Second thing: to actually instantiate a template function you need to call (or explicitly instantiate it) it with some template arguments, but there's no actual code here. – Jack Jan 28 '19 at 21:08
  • `#include implimentation.H` and `#include generic_alg.H` won't even compile at all. Post a [mcve] reproducing your problem as required here please. – πάντα ῥεῖ Jan 28 '19 at 21:10
  • @Jarod42 And even more typos. That question isn't really self contained and should be closed instead of making asumptions about the typos. – πάντα ῥεῖ Jan 28 '19 at 21:22
  • `#include trait_implementation.H.H ` and `#include generic_alg.H` still won't compile. Post real code please! – πάντα ῥεῖ Jan 28 '19 at 21:34
  • @πάνταῥεῖ Fixed some issues. Added online compiler example, but I can't split up the code into files that I know of. Fixed typos (I think). But somebody already posted an answer that Jack stated. I only have a question in the comment section below. – Andre Marin Jan 28 '19 at 21:39
  • @user1945925 You didn't fix the typos I mentioned. – πάντα ῥεῖ Jan 28 '19 at 21:41

1 Answers1

2

#include is, for most practical purposes, a request to dump the contents of the include-ed file directly into your source code.

So even though generic_alg.H uses stuff it doesn't define or include, the only thing getting directly compiled is main.C, and the complete definition from trait_implementation.H is dumped into main.C directly before generic_alg.H, so the definition exists when it gets around to compiling the code from generic_alg.H.

Even though it works, it's still a bad idea, because now every source file that uses generic_alg.H must explicitly include trait_implementation.H first, and there is no obvious documentation making that dependency clear.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • Thanks for the response. I'm not sure of a good approach. I wanted a generic_alg.H to contain general algorithms, and they only differ by thier "traits" data (implmentation.H). I wanted to implement the traits in their specific folder path (which are consequently different code bases). I wanted to split them up like this so that all the codebases don't pick up *all* defined traits. Only the respective traits that are needed for them – Andre Marin Jan 28 '19 at 21:26
  • Any thoughts on a better method to achieve the same result? – Andre Marin Jan 28 '19 at 21:33
  • @user1945925: Typically this is done through [`.tpp` files](https://stackoverflow.com/q/44774036/364696), where the implementation is written in a separate file that is `#include`-ed at the end of the header. Since, as mentioned, `#include` is replaced by the contents of the file you include, this is, from the compilers perspective, equivalent to putting everything in the header, but it has the advantage of explicitly separating API (in the header file itself) from implementation (in the `.tpp` file); the separation is for humans, not the compiler. – ShadowRanger Jan 28 '19 at 22:39
  • Very interesting. It seems hardly different than including the declaration of a template class to another header that has its definition. The only difference being that the second header file I'm referring to would be called .tpp from your link. But I think I understood that my approach would then make it to where everybody would *have to know* to include the second header only, not the first. Which goes back to your original post, that both headers have to be included everywhere (even if I try to hide that in its own header), can be cumbersome and lead to confusion – Andre Marin Jan 29 '19 at 06:13