Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Restrict C++ Template argument to be inside a namespace

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?

like image 903
DuduArbel Avatar asked Dec 07 '25 07:12

DuduArbel


1 Answers

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

Notes

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].

like image 197
Jan Schultke Avatar answered Dec 08 '25 20:12

Jan Schultke