gpt4 book ai didi

c++ - 检查类型是否来自特定命名空间

转载 作者:行者123 更新时间:2023-12-01 23:20:46 27 4
gpt4 key购买 nike

我想检查类型是否来自特定 namespace 。这是我想到的:

#include <utility>

namespace helper
{
template <typename T, typename = void>
struct is_member_of_sample : std::false_type
{
};

template <typename T>
struct is_member_of_sample<
T,
decltype(adl_is_member_of_sample(std::declval<T>()))> : std::true_type
{
};
}

namespace sample
{
template <typename T>
auto adl_is_member_of_sample(T && ) -> void;
}

// -- Test it

namespace sample
{
struct X;
}

struct Y;

static_assert(helper::is_member_of_sample<sample::X>::value, "");
static_assert(not helper::is_member_of_sample<Y>::value, "");

int main(){}

只要没有人将 adl_is_member_of_sample 添加到自己的命名空间(甚至全局命名空间)中,这种方法就可以正常工作。当然,我必须为我想要测试的每个 namespace 创建这样的构造。

是否有更好的方法来在编译时检查类型是否来自特定命名空间?

<小时/> 基本原理或“我为什么想要那个”:

在 EDSL 中,我在编译时检查类型特征,以查看某些表达式是否有效。其中一些类型特征相当简单:如果一个类具有 using is_numeric = void,那么我将其视为数字表达式。工作正常。

is_numeric 不过很通用。其他人也可能会使用它。因此,我考虑通过检查类型是否来自预期的命名空间来支持该特征。

最佳答案

有一种(特定于编译器的)方法来测试类型是否位于某个命名空间中,但我会让您决定它是否比您的更好:

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

我针对 MSVC2015 和一些随机在线 Clang 编译器和 GCC 6.1.0 进行了测试。

想法:

  • 测试接受来自命名空间样本和任何子命名空间的类和结构。
  • 它不会遇到您的解决方案的缺点
  • 您可能希望构建 std::decay_t 以删除 CV 限定符。
  • 显然代码需要 >=C++14 编辑:不再需要了,C++11 就足够了
  • 没有人喜欢宏编辑:删除了大部分宏
  • 代码不太可移植,很可能需要针对某些编译器和编译器版本的额外分支。解决方案是否可以接受取决于您的要求

编辑:重构代码以使其更加清晰并添加 GCC 支持。此外,现在可以将要测试的命名空间作为参数传递

关于c++ - 检查类型是否来自特定命名空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61031239/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com