It depends. The default argument does not change the definition of the template, it is the same. But it does change the definition of things that use the template when they provide no argument.
Consider:
// d.hpp
struct Broken {
x<> member;
};
And uses of that header:
template <bool = true> class x;
#include "d.hpp"
// use Broken
template <bool = false> class x;
#include "d.hpp"
// Use Broken
Now your program is in violation of the ODR as one translation unit sees Broken
as containing a x<true>
while a different translation unit sees Broken
as containing a x<false>
.
A simpler safer approach would be to declare a constant in your .cpp's and don't modify the template:
// b.cpp
#include "a.hpp" // no default argument
const bool default = true;
// any use of x<> becomes x<default> in the rest of the code
// similarly for c.cpp
The definition of the template is the same in all translation units and you get some effect similar to what you want. Note that default
there has internal linkage so the different default
objects would not cause a violation of the ODR.
The same kind of caution applies here as before, if you substitute the definition of Broken
to use default
and the value is defined to be different in different translation units, it will still be a violation of the ODR rule.