You can test whether the namespace
is accessible (looked up by the compiler), via ADL, from the type.
Suppose that we want to check if type A
comes from namespace foo
, we can try to use a type that appears only in foo
(e.g. a generic function foo::foo_inner_func(T&&)
) via the use of A
to see if we reach the namespace. If we do it in a SFINAE context then this can result with the answer we are looking for: whether namespace foo
is accessible via A
.
In many cases that would be the answer of whether the type belongs to this namespace, but in some cases it may identify a namespace as accessible by ADL even though the type doesn't come from this namespace. For example if A
is from namespace foo
and B
which derives from A
is from another namespace, B
still "sees" foo
via ADL. Also std::vector<A>
"sees" foo
via ADL (and also "sees" std
via ADL).
The idea of using ADL was already presented here: Check if a type is from a particular namespace.
Here is the macro version that allows querying any type (almost) for any namespace (almost):
#define create_ns_checker(ns) \
namespace ns { \
template <typename T> \
constexpr std::true_type ns##FindmeNsADLHelper(T&&); \
} \
namespace ns##_type_traits { \
class ns##SecondBestMatchType {}; \
class ns##BestExactMatchType : public ns##SecondBestMatchType {}; \
namespace helpers { \
template <typename T> \
auto TestNs(ns##_type_traits::ns##BestExactMatchType) \
-> decltype(ns##FindmeNsADLHelper(std::declval<T>())); \
template <typename T> \
auto TestNs(ns##_type_traits::ns##SecondBestMatchType) \
-> std::false_type; \
} \
template <typename T> \
constexpr bool ns##IsFindmeNs() { \
return decltype(helpers::TestNs<std::decay_t<T>> \
(ns##BestExactMatchType{}))::value; \
} \
}
#define is_in_ns(Type, ns) \
(ns##_type_traits::ns##IsFindmeNs<Type>())
A small printing utility:
#define print_is_in_ns(Type, ns) \
[]() { \
std::cout << #Type << " in " << #ns << ": " \
<< is_in_ns(Type, ns) << std::endl; \
}()
Creating the checkers with the macro:
create_ns_checker(findme)
create_ns_checker(other)
create_ns_checker(std)
Checking it for the following types:
namespace other {
struct B {};
}
struct C {};
namespace findme {
struct A {};
namespace inner {
struct A {};
}
create_ns_checker(inner)
}
Testing in findme context:
namespace findme {
void test() {
using namespace other;
// add the below in and the results change, as it should!
// using inner::A;
using std::string;
std::cout << std::boolalpha;
print_is_in_ns(int, std); // false
print_is_in_ns(string, std); // true
print_is_in_ns(A, findme); // true
print_is_in_ns(A, inner); // false
print_is_in_ns(inner::A, findme); // false
print_is_in_ns(inner::A, inner); // true
print_is_in_ns(B, findme); // false
print_is_in_ns(B, other); // true
print_is_in_ns(C, findme); // false
}
}
Testing in main:
int main() {
using std::string;
using findme::A;
std::cout << std::boolalpha;
print_is_in_ns(int, std); // false
print_is_in_ns(string, std); // true
print_is_in_ns(string, findme); // false
print_is_in_ns(findme::A, findme); // true
print_is_in_ns(findme::inner::A, findme); // false
print_is_in_ns(other::B, findme); // false
print_is_in_ns(other::B, other); // true
print_is_in_ns(C, findme); // false
print_is_in_ns(std::vector<A>, findme); // falsely says true :-(
print_is_in_ns(std::vector<A>, std); // true
std::cout << "-----------------" << std::endl;
findme::test();
}
Code: https://godbolt.org/z/8Ed89v