Check if a type is from a particular namespace

前端 未结 3 1176
你的背包
你的背包 2020-12-02 18:37

I would like to check if a type is from a particular namespace. Here is what I came up with:

#include 

namespace helper
{
  template 

        
相关标签:
3条回答
  • 2020-12-02 18:49
    std::cout << "I am " << __PRETTY_FUNCTION__ << " function." << std::endl; 
    

    should print

    namespace::class::function.
    
    0 讨论(0)
  • 2020-12-02 19:14

    There is a (compiler specific) way to test whether a type is in a certain namespace, but I'll let you decide whether it is better than yours or not:

    #include <utility>
    #include <type_traits>
    
    namespace helper
    {
    class ctstring
    {
    public:
      constexpr ctstring(const char* string) : _string(string)
      {
      }
    
      constexpr const char* c_str() const
      {
        return _string;
      }
    
      constexpr bool begins_with(const ctstring other) const
      {
        return !*other.c_str() ||
               (*_string && *_string == *other.c_str() &&
                ctstring(_string + 1).begins_with(other.c_str() + 1));
      }
    
    private:
      const char* _string;
    };
    
    template <typename T>
    constexpr bool is_type_in_namespace(const ctstring name)
    {
    #if defined(_MSC_VER)
    #define PRETTY_FUNCTION_OFFSET_1 \
      (sizeof("void __cdecl helper::is_type_in_namespace<struct ") - 1)
    #define PRETTY_FUNCTION_OFFSET_2 \
      (sizeof("void __cdecl helper::is_type_in_namespace<class ") - 1)
    
      return ctstring(__FUNCSIG__ + PRETTY_FUNCTION_OFFSET_1).begins_with(name) ||
             ctstring(__FUNCSIG__ + PRETTY_FUNCTION_OFFSET_2).begins_with(name);
    
    #undef PRETTY_FUNCTION_OFFSET_1
    #undef PRETTY_FUNCTION_OFFSET_2
    #elif defined(__clang__)
      return ctstring(__PRETTY_FUNCTION__ +
                      (sizeof("bool helper::is_type_in_namespace(const "
                              "helper::ctstring) [T = ") -
                       1))
        .begins_with(name);
    #elif defined(__GNUC__)
      return ctstring(__PRETTY_FUNCTION__ +
                      (sizeof("constexpr bool "
                              "helper::is_type_in_namespace(helper::ctstring) "
                              "[with T = ") -
                       1))
        .begins_with(name);
    #else
    #error "Your compiler is not supported, yet."
    #endif
    }
    }
    
    // -- Test it
    
    namespace sample
    {
    struct True_X;
    
    class True_Y;
    
    template <typename>
    class True_T;
    
    template <typename A>
    using True_U = True_T<A>;
    }
    
    struct False_X;
    
    class False_Y;
    
    template <typename>
    class False_T;
    
    template <typename A>
    using False_U = False_T<A>;
    
    void test1()
    {
      static_assert(helper::is_type_in_namespace<sample::True_X>("sample::"), "1");
      static_assert(helper::is_type_in_namespace<sample::True_Y>("sample::"), "2");
      static_assert(helper::is_type_in_namespace<sample::True_T<int>>("sample::"), "3");
      static_assert(helper::is_type_in_namespace<sample::True_U<int>>("sample::"), "4");
      static_assert(!helper::is_type_in_namespace<False_X>("sample::"), "5");
      static_assert(!helper::is_type_in_namespace<False_Y>("sample::"), "6");
      static_assert(!helper::is_type_in_namespace<False_T<int>>("sample::"), "7");
      static_assert(!helper::is_type_in_namespace<False_U<int>>("sample::"), "8");
    }
    
    namespace sample
    {
    void test2()
    {
      static_assert(helper::is_type_in_namespace<True_X>("sample::"), "1");
      static_assert(helper::is_type_in_namespace<True_Y>("sample::"), "2");
      static_assert(helper::is_type_in_namespace<True_T<int>>("sample::"), "3");
      static_assert(helper::is_type_in_namespace<True_U<int>>("sample::"), "4");
      static_assert(!helper::is_type_in_namespace<::False_X>("sample::"), "5");
      static_assert(!helper::is_type_in_namespace<::False_Y>("sample::"), "6");
      static_assert(!helper::is_type_in_namespace<::False_T<int>>("sample::"), "7");
      static_assert(!helper::is_type_in_namespace<::False_U<int>>("sample::"), "8");
    }
    
    namespace inner
    {
    void test3()
    {
      static_assert(helper::is_type_in_namespace<::sample::True_X>("sample::"), "1");
      static_assert(helper::is_type_in_namespace<::sample::True_Y>("sample::"), "2");
      static_assert(helper::is_type_in_namespace<::sample::True_T<int>>("sample::"), "3");
      static_assert(helper::is_type_in_namespace<::sample::True_U<int>>("sample::"), "4");
      static_assert(!helper::is_type_in_namespace<::False_X>("sample::"), "5");
      static_assert(!helper::is_type_in_namespace<::False_Y>("sample::"), "6");
      static_assert(!helper::is_type_in_namespace<::False_T<int>>("sample::"), "7");
      static_assert(!helper::is_type_in_namespace<::False_U<int>>("sample::"), "8");
    }
    }
    }
    
    void test4()
    {
      using namespace sample;
    
      static_assert(helper::is_type_in_namespace<True_X>("sample::"), "1");
      static_assert(helper::is_type_in_namespace<True_Y>("sample::"), "2");
      static_assert(helper::is_type_in_namespace<True_T<int>>("sample::"), "3");
      static_assert(helper::is_type_in_namespace<True_U<int>>("sample::"), "4");
    }
    
    int main(int argc, char* argv[])
    {
      test1();
      sample::test2();
      sample::inner::test3();
      test4();
      return 0;
    }
    

    I tested this for MSVC2015 and some random online Clang compiler and GCC 6.1.0.

    Thoughts:

    • The test accepts classes and structs from namespace sample and any sub-namespace.
    • It doesn't suffer the drawbacks of your solution
    • You might want to build in std::decay_t to remove CV qualifiers.
    • Obviously the code requires >=C++14 Edit: Not any more, C++11 is enough
    • Nobody likes macros Edit: Removed most macros
    • The code isn't very portable and most likely needs additional branches for certain compilers and compiler versions. It is up to your requirements if the solution is acceptable

    Edit: Refactored code to make it more clear and added GCC support. Also, the namespace to test for can now be passed as a parameter

    0 讨论(0)
  • 2020-12-02 19:15

    Unfortunately this technique works only for non-template types. For template types, ADL also checks the namespaces of the template arguments. Then it collects a list of class or function templates (depending on the context ADL is invoked from) and selects the best candidate.

    A better solution would be to add an explicit check to the types whose membership in a namespace you want to check. For example, you could derive all types from a certain class or add a special member to each of them. This would be much clearer, easier to understand and maintain solution.

    0 讨论(0)
提交回复
热议问题