4

对于 C++ 类型,<type_traits>标头为我们提供了许多有用的编译时反射功能。例如std::is_base_of<B, D>::value,在编译时确定是否BD.

我想知道是否可以按照类似的方式检测命名空间成员资格?例如,给定一个N具有类型的名称空间,有没有一种方法可以使用表单的宏表达式T来确定是否T 包含在其中。NIS_NAMESPACE_MEMBER_OF(T,N)

我更喜欢通过任何类型的 SFINAE / ADL 类型的技巧来获得编译时答案。或者,如果不可能,某种推理为什么标准不允许这样做。

一个不可移植和运行时的 hack 将是 regex typeid(T).name()for N,但这相当乏味而且不是在编译时。

EDIT1:正如 K-ballo 所指出的,命名空间不能用作模板参数,因此类型特征似乎是不可能的。

EDIT2:这是K-ballo暗示的骨架:在那里可以(或不能?)进行哪些漂亮的测试?

#define IS_NAMESPACE_MEMBER_OF(T, N) \
                                     \
// global declaration                \
void test(T);                        \
                                     \
// namespace declaration             \
namespace N {                        \
    void test(T);                    \
}                                    \
                                     \
// some clever name lookup / sizeof / SFINAE test!     
4

2 回答 2

4

命名空间不是有效的模板参数,因此它永远不可能是类特征。也许你可以用宏做一些晦涩的事情。您可以在测试命名空间中注入函数并使用 ADL 和sizeof/decltype技巧来查看选择了哪个重载。

于 2012-05-18T18:15:29.580 回答
1

您可以通过 ADL 从类型中测试是否namespace可访问(由编译器查找)。

假设我们要检查类型是否A来自namespace foo,我们可以尝试使用只出现在foo(例如泛型函数foo::foo_inner_func(T&&))中的类型,通过使用A来查看我们是否到达命名空间。如果我们在 SFINAE 上下文中执行此操作,那么这可能会导致我们正在寻找答案:是否namespace foo可以通过A.

在许多情况下,这将是类型是否属于此命名空间的答案,但在某些情况下,它可能会将命名空间标识为可由 ADL 访问,即使该类型并非来自此命名空间。例如,if Ais fromnamespace fooBwhich 派生自Ais from 另一个命名空间,仍然通过 ADL B“看到” 。foo也通过 ADL std::vector<A>“看到” foo(也通过 ADL“看到” std)。

这里已经提出了使用 ADL 的想法:检查类型是否来自特定的命名空间

这是允许查询任何类型(几乎)任何命名空间(几乎)的宏版本:

#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>())

一个小型打印实用程序:

#define print_is_in_ns(Type, ns) \
[]() { \
    std::cout << #Type << " in " << #ns << ": "  \
              << is_in_ns(Type, ns) << std::endl; \
}()

使用宏创建检查器:

create_ns_checker(findme)
create_ns_checker(other)
create_ns_checker(std)

检查以下类型:

namespace other {
    struct B {};
}

struct C {};

namespace findme {
    struct A {};

    namespace inner {
        struct A {};
    }
    create_ns_checker(inner)
}

在 findme 上下文中进行测试:

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
    }
}

主要测试:

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();
}

代码:https ://godbolt.org/z/8Ed89v

于 2020-09-24T17:49:53.873 回答