I want to exclude some headers from my include chain after having used them. From what I know there is no exclude "header.h" in c++11.
Pseudo Code Wishful thinking:
#include "the_bad_header.h" //long includechain with later unused declarations
class bulky { ... };
constexpr std::size_t bulkysize = sizeof(bulky);
forget everything included and class bulky and remember only bulkysize
My example where the problem becomes evident follows. Please don't argue this is not a serious problem. The Example is broken down to show the minimal abstract language usage. I will describe the old fashioned solutions and their disadvantages too.
Old style solution
justanotherheader.h:
class bulkywrap
{
public:
bulkywrap();
protected:
friend class bulkywrap_pImpl;
bulkywrap_pImpl *const pImpl; //opaque pointer, private implementation
};
justanothercppunit.cpp:
#include "justanotherheader.h"
#include "boost/lotsofheaders.hpp"
//#include more and more headers of highly complex libraries so adding millions of known types and other identifiers, macros, and so on
class bulkywrap_pImpl
{
//lots of members of types used from the other libraries
};
bulkywrap::bulkywrap()
: pImpl( new bulkywrap_pImpl() )
{}
My current Solution
justanotherheader.h:
#include "stdint.h" // this is the only header I like to use, but also unnecessary.
#define UNKNOWNSIZE 12345
class bulkywrap
{
public:
bulkywrap();
protected:
friend class bulkywrap_pImpl;
bulkywrap_pImpl *const pImpl; //opaque pointer, private implementation
uint8_t pImpl_Placement[UNKNOWNSIZE]; //placement new for pImpl
};
justanothercppunit.cpp:
#include "justanotherheader.h"
#include "boost/lotsofheaders.hpp"
//#include more and more headers of highly complex libraries so adding millions of known types and other identifiers, macros, and so on
class bulkywrap_pImpl
{
//lots of members of types used from the other libraries
};
bulkywrap::bulkywrap()
: pImpl( new(this->pImpl_Placement) bulkywrap_pImpl() ) //using this here is safe
{}
So, the code above is working. The advantages are: hiding complexity and having no runtime dynamic memory indirections. Huh? I mean, the placement new allows the whole object to be put on stack and all member addresses are known at compile time. My attempt is to have best performance while using interface design of opaque pointer.
If you think: "this performance advantage is not worth the thinking effort." then please leave that question.
My expected Solution
justanotherheader.h:
#include "stdint.h" // this is the only header I like to use, but also unnecessary.
constexpr std::size_t get_bulkywrap_pImpl_Size( void ); //constexpr function forward declaration
extern constexpr std::size_t bulkywrap_pImpl_Size; //constexpr literal forward declaration with external initialization
class bulkywrap
{
public:
bulkywrap();
protected:
friend class bulkywrap_pImpl;
bulkywrap_pImpl *const pImpl; //opaque pointer, private implementation
uint8_t pImpl_Placement[get_bulkywrap_pImpl_Size()]; //undefined constexpr used
uint8_t pImpl_Placement[bulkywrap_pImpl_Size]; //alternative to above. undefined constexpr used
};
justanothercppunit.cpp:
#include "justanotherheader.h"
#include "boost/lotsofheaders.hpp"
//#include more and more headers of highly complex libraries so adding millions of known types and other identifiers, macros, and so on
class bulkywrap_pImpl
{
//lots of members of types used from the other libraries
};
constexpr std::size_t get_bulkywrap_pImpl_Size( void )
{
return sizeof(bulkywrap_pImpl);
}
constexpr std::size_t bulkywrap_pImpl_Size = sizeof(bulkywrap_pImpl);
bulkywrap::bulkywrap()
: pImpl( new(this->pImpl_Placement) bulkywrap_pImpl() ) //using this here is safe
{}
In my current solution I need to verify the sizeof(bulkywrap_pImpl) and adjusting UNKNOWNSIZE manually.
I think it is currently not possible to get any information from a compilationunit to others. I know this is typically intended by good reason, but this limits the possibilities of c++11.
I want to point out:
jtc1 sc22 wg21 paper n3337
jtc1 sc22 wg21 paper n3308
Please help me to find information weather and why the standard does not allow this.
But furthermore I would like to find a solution of how to export some literal constant during compiliation time out of a compileunit into another compileunit. It's just a literal, so all statements and expressions are not affected by it. Thus compilation does not depend where the size of the array comes from.
My suggestion results in some work for the ISO-jtc1-sc22-wg21 and the compiler developers, but I don't see any relevant difference between template and constexpr since every definition must appear in the same translationunit. This makes modular programming and clean interfaces bogus.
And no: I don't want to use preprocessor macros, dynamic new or virtual member functions. Of importance is maximal const-correctness, since the size of the class is const.
Please help
you can't have both "compile-time" and "from another compilation unit" at the same time. also it's not clear why do you need to forget successfully parsed header. parsing time already consumed. i suggest you to create another header with size constant, include it from both files, and add static_assert to pimpl file, checking that constant >= sizeof(pimpl). you can generate this header as part of your build system by compiling source file including pimpl and doing cout <<sizeof(pimpl). also i suggest you to not waste time and space for pimpl pointer and replace it with member function, returning address of properly cast buffer. also you failed to show where you call pimpl's destructor. also implementing assignment/copy/move/swap will be a lot of fun
use static_assert in cpp to check that size declared in header >= size of impl class
Related
All the solutions to circular include dependencies I've seen just say in "this particular case" the full class definition isn't necessary since "you" are only using pointers to that class.
I encountered this problem and fixed it using forward declarations.
I am wondering what are you supposed to do when you need the specific definition of the other class in both classes.
Also, why does using a pointer to the class allow you use a forward declaration instead of a class definition?
In what cases would you need the specification known beforehand for both classes?
One impossible case is the following:
class A
{
B m_b;
};
class B
{
A m_a;
};
But this is impossible since the size of class A depends on the size of class B, but the size of class B depends on the size of class A. You'll also get an infinite series A myA; myA.m_b.m_a.m_b.m_a.... when you try to construct either.
If you use pointers, you don't need to know the size of either; a pointer is always the same size depending on the platform your are on. And the series disappears because objects in the heap need to be created explicitly.
I am wondering what are you supposed to do when you need the specific
definition of the other class in both classes.
It can be done with forward declarations and deferred definitions in modern compilers. Many older compilers only allow pointers & references to forward declared types.
Here's a contrived example:
A.hpp
class B;
class A
{
public:
int32_t Value;
A(int32_t value) : Value(value) { }
int32_t Add(B b) const;
}
B.hpp
#include "A.hpp"
class B
{
public:
int32_t Value;
B(int32_t value) : Value(value) { }
int32_t Sub(A a) const;
}
AB.hpp
#include "A.hpp"
#include "B.hpp"
inline int32_t A::Add(B b) const
{
return this->Value + b.Value;
}
inline int32_t B::Sub(A a) const
{
return this->Value - a.Value;
}
Also, why does using a pointer to the class allow you use a forward
declaration instead of a class definition?
Forward declarations are just names to the compiler. The concept exists so you can use types that haven't been defined yet. This is necessary because of the way C++ parses code, an artifact of the C language it inherits a great deal from. C++ parsers are really just forward-only text processors that inject text when you #include and use macros. It's a conceptually simple model that made C/C++ compilers easier to write in the early days. Contrast this to C#/Java where you just use using/import and happily create circular dependencies between classes with simple syntax.
Pointers are really just integers, similar to short and int, but with special semantics enforced by the language and a fixed size known at compile time based on the CPU architecture. This makes pointer declarations very simple for compilers to deal with.
Forward declaration facilitates circular dependencies and implementation hiding(which also happens to speed up compilation time). Consider the pimpl idiom. Without forward declarations there's no type-safe way to hide implementation details.
I want to write a C-wrapper around an existing C++ codebase. So I need to implement some C-API functions that merely forward their operations to the corresponding C++ methods.
My problem is, I cannot figure out how to implement a forward-defined struct by means of an existing class:
//Foo.hpp
namespace myLib {
struct Foo {
//some meaningful C++ body
};
}
//foo.h
//#ifdef __cplusplus etc. left out
extern "C" {
struct myLib_foo;
myLib_foo* mkfoo();
//etc.
}
//foo.cpp
extern "C" {
#include "Foo.hpp"
#include "foo.h"
typedef myLib_foo myLib::Foo; //this does not work
myLib_foo* mkfoo() { return new myLib::Foo(); }
}
In this situation, the C-API can and shall only work with pointers to myLib::Foo, which obviously works well, if I define myLib_foo as a new struct inside foo.cpp. I guess it also works, if I define a struct myLib_foo somewhere else. Yet, since I want to keep my namespaces manageable, I am searching a way to define myLib_foo to be equivalent to some existing (and completely defined) struct. This, however does not work, since my compiler refuses the code above with "typedef redefinition with different types". Apparently, it distinguishes between type-aliases and structs.
Is there even a way to achieve what I want or does C++ have no means for real type-aliases?
edit:
By the answer below, I figured I can use inheritance plus static_cast:
//foo.cpp
extern "C" {
#include "Foo.hpp"
#include "foo.h"
struct myLib_foo : public myLib::Foo {}; //this does work
myLib_foo* mkfoo() { return static_cast<myLib_foo*>(new myLib::Foo()); }
}
The C code does not ever need a definition of the struct myLib_foo that it sees.
It handles it only through pointers and functions.
On the C++ side a simple implementation is a struct containing a pointer to the "real" object that it represents. You then define it in the ordinary way (in the C++ code), but of course with the name already established for the C code usage.
If you want to avoid even that little inefficiency, to hand out real object pointers to the C code, well then you have essentially two options:
reinterpret_cast, or
static_cast with the not-quite-C struct as a (possibly empty) base class.
But I would go for the simple implementation of myLib_foo as a struct with a pointer to the real one. The KISS principle: Keep It Simple, Stupid*. On second thoughts, to avoid allocation and deallocation issues, and to also avoid a formal dependency on the compiler (even if that would just be academic, a formality), I would go for the static_cast. For thinking about what it all entails, this seems simplest.
*: Oh, the last few times I mentioned this principle on SO, those answers were heavily downvoted. That has also happened when I have (correctly) proposed macros as solutions. I think one should be technically honest and ignore the general SO readership, so I mention it anyway.
Is there any reason why one shouldn't #include another file from within a class declaration when that class defines numerous private constants?
I'm writing a class which adheres to a simple state-transition system and defines a processing schedule consisting of several states, each of which consist of a series of steps. Because the class has to refer to these states and steps in various functions (for example, when determining which processing to apply based on the current state and step), I end up defining a bunch of private enum's within the class's declaration to make the implementation readable (so I can refer to things like kStates_ModeTransition and kStateSteps_ModeTransition_PrepareNewSetup etc, rather than just using the raw integer values associated with these states and steps).
As the list of states and state-steps has grown longer, this collection of enum's has become a fairly long, awkward chunk of code in the middle of the class declaration, and I feel these constants are more connected to the implementation than the interface - a user of the class doesn't necessarily have to know about them. Is there any reason why I shouldn't move all of these enum's to another file and then just #include that file into the private section of the class declaration? I haven't encountered another situation where it seemed appropriate to use a #include within the body of a class, so I'm wondering if there's a better way to handle this or any particular reason such an #include would be bad form. Furthermore, is there any sensible standard file extension to use on such a file, used only for text insertion (it isn't really a header...)? Just .txt?
Thanks!
Edit: A bit more to see if one of the mentioned alternatives completely dissolves my dilemma:
Trying to stick only to the essentials, here's an example of my current structure
// Processor.h
class Processor
{
public:
Processor();
void Process( float* input, float* output, int numSamples );
private:
// List of possible states
enum
{
kStates_Default,
kStates_SettingChangeImmediate,
kStates_SettingChangeCrossfade,
kStates_SpecialProcessing,
kStates_NumStates
};
// Lists of steps for each state...
enum
{
kStateSteps_Default_PrepareInput,
kStateSteps_Default_CalculateIntermediateValues,
kStateSteps_Default_CalculateOutput,
kStateSteps_Default_NumSteps
};
// Imagine more lists for other states here, with comments...
// Becoming quite long...
// Private functions used in implementing various processing steps
// (some are used by multiple state-steps in varying ways)
void PrivateFunction1();
void PrivateFunction2();
// Some member variables here
};
This is used in a real-time processing context in order to better balance DSP load when performing block-processing tasks. In reality, this class inherits from a base class which handles the actual scheduling of calls to Process, updating the current state and state-step as needed. Process() then consists of a switch statement which performs certain processing functions and IO based on the current state and state-step of the object.
The values declared in the enums are used within Process() and other private member functions inside processor.cpp, and nowhere else. I've declared them as private member variables to scope them to within the class. Is there a way to declare them inside the .cpp and achieve the same scoping? These are all meant to be constant integers optimized away at compile time and are essentially being used as #define 's - I just don't want to use macros.
All includes are just text inclusion. Since the file you're including contains C++ syntax, it should have a C++ header extension (.h or .hpp or etc.).
You may not need to include it into the declaration (I could speak to this more certainly if you post some code) ... you could just include it into the implementation files, and declare any enum member variables as int ... using typedefs (aliases for int) if you want to give them descriptive type names. Or if you're using C++11, you can forward declare your enum types without defining them, and then you enum member variables will be typesafe, preventing assignment of the wrong sort of enum value.
As for your question of whether there's a reason why you shouldn't move the enums out of your class declaration into another file and include that file: one can always invent reasons not to do things, such as "our Coding Standards say never to include a file other than at top level, at the top of the file", but if such arbitrary reasons don't apply to you then no, there's no reason. Do what makes the most sense in terms of code maintainability.
Using an #include in the middle of a class is highly irregular and could cause problems. It's much better if you declare your constants in either their own namespace or class.
For instance, this is a bad idea:
class Foo
{
#include "foostuff.h"
};
The more typical pattern is:
#include "foostuff.h"
class Foo
{
void bar(int x = FooStuff::const_x);
};
Inside foostuff.h you'd be careful to namespace things so they won't collide with other parts of your application.
The C++ way of doing things encourages the re-use of constants between different parts of your application instead of using #define to create macros that, once expanded, have no particular association.
All "include" files should be either .h for plain C or .hpp for anything that requires a C++ capable compiler to interpret. Anything else is non-standard and will, at the very least, lead to scorn from anyone who has to maintain your code.
New C++11 enum class may be forward declared and real definition moved to implementation. That will clean the mess and reduce annoyance.
// Procesor.hpp
class Processor
{
public:
Processor();
void Process( float* input, float* output, int numSamples );
private:
// Type of possible states
enum class kState;
kState somethingDealingWithState( kState s );
};
// Processor.cpp
// List of possible states
enum class Processor::kState
{
Default,
SettingChangeImmediate,
SettingChangeCrossfade,
SpecialProcessing,
NumStates
};
Processor::kState Processor::somethingDealingWithState( kState s )
{
if ( s == kState::Default )
{
return kState::SpecialProcessing;
}
return kState::Default;
}
In the end, it seems the best way to achieve equivalent functionality while gaining the benefit of separating the enumeration details into the .cpp implementation file is to use a forward declaration of a struct within the private portion of the class, and to then define that struct to contain the desired enum's from within the .cpp file.
// Processor.h
class Processor
{
public:
Processor();
void Process( float* input, float* output, int numSamples );
private:
struct States; // Used to scope State enum to within class
struct StateSteps; // Used to scope StateStep enums to within class
// Other stuff...
}
// Processor.cpp
struct Processor::States
{
enum
{
Default,
SettingChangeImmediate,
SettingChangeCrossfade,
SpecialProcessing,
NumStates
};
}
struct Processor::StateSteps
{
enum
{
Default_PrepareInput,
Default_CalculateIntermediateValues,
Default_CalculateOutput,
Default_NumSteps
};
enum
{
SettingChangeImmediate_FirstStep,
// ... other state-steps...
};
};
Here's why I think this structure is best in this particular use-case:
All enum listings are moved to the .cpp file, out of the middle of the header as desired, and additional StateStep enums which contain the same values (say, counting up from 0) may be added into the definition of the StateSteps struct without disturbing the .h header (while we could add entries to a forward-declared enum class, we couldn't have repeats of the same value and would need to add another enum class to the header).
All of the enums are scoped within the private portion of the class as before (albeit within another struct as well).
Enums which are being used to define compile-time integer constants may remain anonymous and not strongly typed enum class constructs, which may mislead others as to how the enums are being used (in the current use-case, we WANT to be able to compare different stateStep enum values to the same integer currentStep, depending on the current state, as we could with the originally defined anonymous enums).
Previous answers helped get me to this conclusion, but I feel that this is a way which most closely duplicates the functionality of the original definitions while moving them out of the .h file!
I have used forward declarations a lot; they help avoid many #includes, improve compilation time and what not. But what if i want to forward-declare a class in the standard library?
// Prototype of my function - i don't want to include <vector> to declare it!
int DoStuff(const std::vector<int>& thingies);
I have heard it's forbidden/impossible to forward-declare std::vector. Now this answer to an unrelated question suggests to rewrite my code this way:
stuff.h
class VectorOfNumbers; // this class acts like std::vector<int>
int DoStuff(const VectorOfNumbers& thingies);
stuff.cpp
// Implementation, in some other file
#include <vector>
class VectorOfNumbers: public std::vector<int>
{
// Define the constructors - annoying in C++03, easy in C++11
};
int DoStuff(const VectorOfNumbers& thingies)
{
...
}
Now, if i use VectorOfNumbers instead of std::vector<int> in all contexts throughout my project, everything is going to be good, and i don't need to #include <vector> in my header files anymore!
Does this technique have major disadvantages? Can the gain of being able to forward-declare vector outweigh them?
If you ever delete a VectorOfNumbers as a std::vector<int> (and since you used public inheritance this conversion is implicit) you've entered the realm of undefined behavior. This is probably more likely to accidentally happen than one might suspect.
I've never personally noticed significant compilation slowdown from just including vector where needed, but if you really want to isolate the include, use a client API interface that doesn't know about the underlying container type (vector) and pimpl the vector include into a single source file.
The reason I wouldn't do this:
const std::vector<int>& a = a_3rd_party_lib::get_data(); // this type is out of your control
DoStuff(a); // you cannot pass it to this function!
You include <vector> in your header file. The <vector> header will have been built to prevent multiple inclusions, so you just include it everywhere you need it.
This works well for the interface for a class, but not for the implementation. If your class has any vector members you must #include <vector> or the class definition will not compile.
Instead of inheritance, you could use composition:
// Implementation, in some other file
#include <vector>
class VectorOfNumbers
{
public:
std::vector<int>& container;
VectorOfNumbers(std::vector<int>& in_container)
: container(in_container)
{
}
};
int DoStuff(const VectorOfNumbers& thingies)
{
std::sort(thingies.container.begin(), thingies.container.end());
// ...
}
The downside is the extra variable name on every access.
Also, you'd need this implementation to be in a header file included by cpps so they will know what they can do with VectorOfNumbers.
Essentially, just making a wrapper for your vector. This is like a light-weight version of PImpl (we only care about avoiding header dependencies so we don't need the full pointer decoupling). It avoids the issues raised by Mark B and ybungalobill.
But I don't think it's really worth it.
Always considering that the following header, containing my templated class, is included in at least two .CPP files, this code compiles correctly:
template <class T>
class TClass
{
public:
void doSomething(std::vector<T> * v);
};
template <class T>
void TClass<T>::doSomething(std::vector<T> * v) {
// Do something with a vector of a generic T
}
template <>
inline void TClass<int>::doSomething(std::vector<int> * v) {
// Do something with a vector of int's
}
But note the inline in the specialization method. It is required to avoid a linker error (in VS2008 is LNK2005) due to the method being defined more then once. I understand this because AFAIK a full template specialization is the same as a simple method definition.
So, how do I remove that inline? The code should not be duplicated in every use of it. I've searched Google, read some questions here in SO and tried many of the suggested solutions but none successfully built (at least not in VS 2008).
Thanks!
As with simple functions you can use declaration and implementation.
Put in your header declaration:
template <>
void TClass<int>::doSomething(std::vector<int> * v);
and put implementation into one of your cpp-files:
template <>
void TClass<int>::doSomething(std::vector<int> * v) {
// Do somtehing with a vector of int's
}
Don't forget to remove inline (I forgot and thought this solution will not work :) ).
Checked on VC++2005
You need to move specialization definition to CPP file.
Specialization of member function of template class is allowed even if function is not declared as template.
There is no reason to remove the keyword inline.
It does not change the meaning of the code in anyway.
If you want to remove the inline for whatever reason the solution of maxim1000 is perfectly valid.
In your comment, though, it seems you believe that the inline keyword means that the function with all his contents gets always inlined but AFAIK that is actually very much dependent on your compiler optimization.
Quoting from the C++ FAQ
There are several ways to designate that a function is inline, some of
which involve the inline keyword, others do not. No matter how you
designate a function as inline, it is a request that the compiler is
allowed to ignore: the compiler might inline-expand some, all, or none
of the places where you call a function designated as inline. (Don’t
get discouraged if that seems hopelessly vague. The flexibility of the
above is actually a huge advantage: it lets the compiler treat large
functions differently from small ones, plus it lets the compiler
generate code that is easy to debug if you select the right compiler
options.)
So, unless you know that that function will actually bloat your executable or unless you want to remove it from the template definition header for other reasons, you can actually leave it where it is without any harm
This is a little OT, but I thought I'd leave this here in case it helps someone else. I was googling about template specialization which led me here, and while #maxim1000's answer is correct and ultimately helped me figure my problems out, I didn't think it was abundantly clear.
My situation is a little different (but similar enough to leave this answer I think) than the OP's. Basically, I'm using a third party library with all different kinds of classes that define "status types". The heart of these types are simply enums, but the classes all inherit from a common (abstract) parent and provide different utility functions, such as operator overloading and a static toString(enum type) function. Each status enum is different from one another and unrelated. For example, one enum has the fields NORMAL, DEGRADED, INOPERABLE, another has AVAILBLE, PENDING, MISSING, etc. My software is in charge of managing different types of statuses for different components. It came about that I wanted to utilize the toString functions for these enum classes, but since they're abstract I couldn't instantiate them directly. I could have extended each class I wanted to use, but ultimately I decided to create a template class, where the typename would be whatever concrete status enum I cared about. Probably some debate can be had about that decision, but I felt like that was a lot less work than extending each abstract enum class with a custom one of my own and implementing the abstract functions. And of course in my code, I just wanted to be able to call .toString(enum type) and have it print the string representation of that enum. Since all the enums were entirely unrelated, they each had their own toString functions that (after some research I learned) had to be called using template specialization. That led me here. Below is an MCVE of what I had to do in order to make this work correctly. And actually my solution was a bit different than #maxim1000's.
This is a (greatly simplified) header file for the enums. In reality, each enum class was defined in it's own file. This file represents the header files that are supplied to me as part of the library I am using:
// file enums.h
#include <string>
class Enum1
{
public:
enum EnumerationItem
{
BEARS1,
BEARS2,
BEARS3
};
static std::string toString(EnumerationItem e)
{
// code for converting e to its string representation,
// omitted for brevity
}
};
class Enum2
{
public:
enum EnumerationItem
{
TIGERS1,
TIGERS2,
TIGERS3
};
static std::string toString(EnumerationItem e)
{
// code for converting e to its string representation,
// omitted for brevity
}
};
adding this line just to separate the next file into a different code block:
// file TemplateExample.h
#include <string>
template <typename T>
class TemplateExample
{
public:
TemplateExample(T t);
virtual ~TemplateExample();
// this is the function I was most concerned about. Unlike #maxim1000's
// answer where (s)he declared it outside the class with full template
// parameters, I was able to keep mine declared in the class just like
// this
std::string toString();
private:
T type_;
};
template <typename T>
TemplateExample<T>::TemplateExample(T t)
: type_(t)
{
}
template <typename T>
TemplateExample<T>::~TemplateExample()
{
}
next file
// file TemplateExample.cpp
#include <string>
#include "enums.h"
#include "TemplateExample.h"
// for each enum type, I specify a different toString method, and the
// correct one gets called when I call it on that type.
template <>
std::string TemplateExample<Enum1::EnumerationItem>::toString()
{
return Enum1::toString(type_);
}
template <>
std::string TemplateExample<Enum2::EnumerationItem>::toString()
{
return Enum2::toString(type_);
}
next file
// and finally, main.cpp
#include <iostream>
#include "TemplateExample.h"
#include "enums.h"
int main()
{
TemplateExample<Enum1::EnumerationItem> t1(Enum1::EnumerationItem::BEARS1);
TemplateExample<Enum2::EnumerationItem> t2(Enum2::EnumerationItem::TIGERS3);
std::cout << t1.toString() << std::endl;
std::cout << t2.toString() << std::endl;
return 0;
}
and this outputs:
BEARS1
TIGERS3
No clue if this is the ideal solution to solve my problem, but it worked for me. Now, no matter how many enumeration types I end up using, all I have to do is add a few lines for the toString method in the .cpp file, and I can use the libraries already-defined toString method without implementing it myself and without extending each enum class I want to use.
I'd like to add that there is still a good reason to keep the inline keyword there if you intend to leave also the specialization in the header file.
"Intuitively, when you fully specialize something, it doesn't depend on a template parameter any more -- so unless you make the specialization inline, you need to put it in a .cpp file instead of a .h or you end up violating the one definition rule..."
Reference: https://stackoverflow.com/a/4445772/1294184