gpt4 book ai didi

关于识别方法签名存在的 C++ 自省(introspection)

转载 作者:行者123 更新时间:2023-12-02 10:03:30 26 4
gpt4 key购买 nike

我想对我使用或过度使用的常用技术进行现代化改造。它静态检查方法签名并调用方法(如果存在)。我的方法比 C++17 早了一段时间 FWIW。

目前,我使用了 Boost 的 Type 特征,例如 BOOST_TTI_HAS_MEMBER_FUNCTION(event)
这允许诸如

template <typename M, typename E>

static inline typename std::enable_if<
has_member_function_event<current_t, void, boost::mpl::vector<M &, const E &>>::value
>::type

event(M &mux, S &g, const E &e) {
auto &node = boost::fusion::at<N>(g);
node.event(mux, e);
...

它工作得很好,但是,你知道,它不是最漂亮的。有没有办法我可以避免宏并加入现代世界的其他人:-)?

问候,

——马特。 (又名恐龙)

最佳答案

简单、直接的 SFINAE 会满足您的需求吗?

这是一个执行各种成员函数的测试函数,检查是否有足够的返回类型和 const 正确性:

template <typename Obj> void exercise(Obj&& obj) {
if constexpr(has_bar(obj)) {
std::cout << "called T bar() -> something or void\n";
obj.bar();
}
if constexpr(converts<int>(has_foo(obj))) {
std::cout << "called int foo() const -> " << obj.foo() << "\n";
}
if constexpr(converts<long>(has_foo(obj, "some text"))) {
std::cout << "called long foo(std::string) -> " << obj.foo("some text") << "\n";
}
}
has_bar实现很简单:
template <typename T>
static constexpr auto has_bar(T&& obj) -> exists<decltype(obj.bar())> { return {}; }
template <typename... T>
static constexpr auto has_bar(T&&...) -> does_not_exist { return {}; }

为了一般允许检查签名并避免重复代码,这里有一个辅助宏(显然是可选的):
#define DEF_HAS_MEMBER(name) \
template <typename T, typename... Args> \
static constexpr auto has_##name(T&& obj, Args&&... args) \
-> exists<decltype(std::forward<T>(obj).name(std::forward<Args>(args)...))> { return {}; } \
template <typename... T> \
static constexpr auto has_##name(T&&...) -> does_not_exist { return {}; }

DEF_HAS_MEMBER(foo)
DEF_HAS_MEMBER(bar)
converts谓词现在是一个超简单的加法:
template <typename T, typename R>
static constexpr auto converts(R) { return std::is_convertible_v<typename R::return_type, T>; }

一切都在一起:

Live On Coliru
#include <string>

#include <type_traits>
#include <iostream>

template <typename R> struct exists : std::true_type { using return_type = R; };
struct does_not_exist : std::false_type { using return_type = void; };

#define DEF_HAS_MEMBER(name) \
template <typename T, typename... Args> \
static constexpr auto has_##name(T&& obj, Args&&... args) \
-> exists<decltype(std::forward<T>(obj).name(std::forward<Args>(args)...))> { return {}; } \
template <typename... T> \
static constexpr auto has_##name(T&&...) -> does_not_exist { return {}; }

DEF_HAS_MEMBER(foo)
DEF_HAS_MEMBER(bar)

struct Everything {
int foo(std::string /*unused*/) { return 42; }
int foo() const { return -1; }
void bar() {}
};

struct Some {
int foo() const { return -2; }
};

template <typename T, typename R>
static constexpr auto converts(R) { return std::is_convertible_v<typename R::return_type, T>; }

template <typename Obj> void exercise(Obj&& obj) {
std::cout << "===== " << __PRETTY_FUNCTION__ << "\n";

if constexpr(has_bar(obj)) {
std::cout << "called T bar() -> something or void\n";
obj.bar();
}
if constexpr(converts<int>(has_foo(obj))) {
std::cout << "called int foo() const -> " << obj.foo() << "\n";
}
if constexpr(converts<long>(has_foo(obj, "some text"))) {
std::cout << "called long foo(std::string) -> " << obj.foo("some text") << "\n";
}
}

int main() {
Everything e;
Everything const ce;
Some s;
Some const cs;

exercise(s);
exercise(cs);
exercise(ce);
exercise(e);
}

打印
===== void exercise(Obj&&) [with Obj = Some&]
called int foo() const -> -2
===== void exercise(Obj&&) [with Obj = const Some&]
called int foo() const -> -2
===== void exercise(Obj&&) [with Obj = const Everything&]
called int foo() const -> -1
===== void exercise(Obj&&) [with Obj = Everything&]
called T bar() -> something or void
called int foo() const -> -1
called long foo(std::string) -> 42

关于关于识别方法签名存在的 C++ 自省(introspection),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61358946/

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