I've been using a dirty trick where I use unnamed namespaces to specify different behavior for each file (it is for unit-testing). It feels like it shouldn't be well-defined, but it works on every major compiler released in the past six years.
I first forward-declare a bunch of classes in an anonymouse namespace:
namespace {
class context_check;
class context_block;
class register_test;
} // namespace
Then I declare a class and make these classes friends:
struct test_case
{
// ...
};
class context {
// ...
private:
// TODO: this feels like ODR-violation...
friend class context_check;
friend class context_block;
friend class register_test;
private:
void add_test(test_case&& test)
{
// ...
}
// ...
};
And in each cpp file I have following declarations (for tha sake of simplicity I copy and pasted them here, but in reality I declare the content of unnamed namespace in a header):
// A.cpp
namespace {
extern context file_context;
class register_test {
public:
register_test(const char* test_name, test_case&& test)
{
file_context.add_test(std::move(test));
}
};
} // namespace
register_test register_test_1( test_case{"test1"} );
// B.cpp
namespace {
extern context file_context;
class register_test {
public:
register_test(const char* test_name, test_case&& test)
{
file_context.add_test(std::move(test));
}
};
} // namespace
register_test register_test_2( test_case{"test2"} );
So each TU has its own definitions of register_test, context_check etc.
Is this well-defined? Feels like it should be an UB...
Seems to violate the following condition required by ODR, as stated on https://en.cppreference.com/w/cpp/language/definition:
None of the exceptions are relevant and lookup for e.g.
context_checkinfriend class context_check;, which is part of the definition ofcontext, finds an internal linkage entity, which cannot be the same if the definition is included in multiple translation units.The actual corresponding rule of the standard can be found e.g. in [basic.def.odr]/13.9 of the post-C++20 draft.