Is there a way to restrict a template type to be part of a certain namespace?
namespace AAA
{
struct CLS_1
{};
}
struct CLS_2
{};
foo<CLS_1>(); // This is Ok
foo<CLS_2>(); // Will not compile - CLS_2 is not inside template AAA
I tried something like this:
template<class T> requires requires(T t) {AAA::T;}
void foo()
{}
but that did not compile. Is there a (simple) way to do so?
You can exploit the fact that argument-dependent lookup will find functions in the same namespace as the argument. Here's how:
namespace AAA {
struct CLS_1 {};
// add a helper function to namespace AAA
template <typename T>
// const volatile& can bind to any value category and cv qualification
void namespace_aaa_membership_tester(const volatile T&) {
// This function should never be instantiated.
// Note that older compilers don't handle static_assert(false) correctly,
// and you have to make the condition dependent on T.
static_assert(false); // (1)
}
} // namespace AAA
struct CLS_2 {};
// define a concept; this could be used as a type constraint for functions
template <typename T>
concept in_aaa = requires (T& t) {
// this expression is only valid for AAA::T
namespace_aaa_membership_tester(t);
};
int main() {
static_assert(in_aaa<AAA::CLS_1>); // OK
static_assert(!in_aaa<CLS_2>); // OK
// Known issue with ADL: this also passes.
static_assert(in_aaa<std::vector<AAA::CLS_1>>); // OK
// Known issue with type aliases: namespace of the type alias
// is irrelevant. This could be considered good or bad.
using type = AAA::CLS_1;
static_assert(in_aaa<type>); // OK
}
See live example at Compiler Explorer
Note that this wouldn't pass for a type AAA::BBB::CLS_1, as only surrounding namespace is considered by ADL, not all parent namespaces recursively. I believe it is impossible to check whether AAA::arbitrary_namespace::CLS_1 is in AAA.
Also keep in mind that anyone can put anything they want into a namespace, so there is very little that can be gained by knowing whether a type T is in AAA in practice.
A more robust way of giving certain classes "extra privileges" is by making them friends of some AAA::Privileged class.
(1) It's okay to have templates that can never be instantiated as the result of static_assert(false) due to a special case in [temp.res.general].
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With