你能切换一个 std::any.type() 吗?

Posted

技术标签:

【中文标题】你能切换一个 std::any.type() 吗?【英文标题】:can you switch over a std::any.type()? 【发布时间】:2020-12-14 15:42:58 【问题描述】:

我想探索如何使用 std::any 而不是 void * 或类似的结构来传递消息。所以我创建了一个示例代码来测试它 - 见下文。

std::any 的使用看起来不错,但我想切换类型以检查 std::any 是哪种类型。这可能是不可能的,我知道我可以使用 if/elseif... 块代替,但是如果我可以创建一个 switch 语句,这样如果我在具有 10-20 种不同类型的实际代码中使用它,那就太好了它会更具可读性。

#include <string>  
#include <iostream>  
#include <sstream>  
#include <any>  
#include <typeindex>  

struct ints  int a1; int b2; ;
struct strings  std::string a"string1"; std::string b"string2"; ;

void send_msg(std::any item)

    switch (item.type().hash_code())       // <------- HERE
    
        case typeid(ints).hash_code():     // <------- HERE
            std::cout << "ints" << std::endl;
            break;
        case typeid(strings).hash_code():
            std::cout << "strings" << std::endl;
            break;
        default:
            std::cout << "unknown type\n";
    


int main()

    strings s;
    send_msg(s);

    ints i;
    send_msg(i);


实时示例:https://godbolt.org/z/xPrMYM

我无法打开 std::any::type 返回的 type_info,但我可以打开 type_info 的 hash_code(),但这不是我希望的 constexpr!

所以我也尝试获取类型信息的地址以及我能找到的一些其他技巧。但到目前为止还没有运气......

有这样的方法吗?

【问题讨论】:

您可能正在寻找std::variantstd::visit Variant 也破坏了正确的对象并且具有类型安全性。 @code_fodder 没错,但any 只是一个不受约束的variant,如果您切换类型表明您想要它是受约束的。 @code_fodder: "我读到它可以用来代替 void 之类的东西*" 它可以。如果您知道将其转换为正确的类型,您可以正确使用void*。您不能使用void*“切换类型”,因此您尝试做的事情也不适用于void* @code_fodder:更重要的是,any 用于these circumstances 【参考方案1】:

如果可能的话,我也会在这里建议一个变体,但针对具体问题:

如果您可以使用 boost 并且 C++17 是您的参考标准:它们提供了扩展的 typeid 处理,也可以用于多个编译时检查,请参阅

https://www.boost.org/doc/libs/1_67_0/boost/type_index/ctti_type_index.hpp

它的底层 rawType 是一个 const char* constexpr,而 typeIndex 本身可以用作 std::type_info 的完美替代品。由于标准保证这些类型标识符的唯一地址,因此即使是简单的地址比较也应该可以在这里进行(不知道为什么这种简化目前在 boost 标头中被注释掉了)。

要与 any 一起使用,您可能必须包装它或使用简单的 own any 类型。

【讨论】:

【参考方案2】:

你问的是std::visit,但是std::any

template<typename... Ts, typename F>
bool visit(F&& f, std::any x)

    auto result = ((x.type() == typeid(Ts) ?
        (std::forward<F>(f)(*std::any_cast<Ts>(&x)), true) : false) || ...);
    return result;

由于std::any 可能包含任何内容,visit 可能会在运行时失败,这就是为什么您当然需要某种方式来报告错误

用作

bool send_msg(std::any x)

    auto f = [](auto&& x)
        std::cout << x << '\n';
    ;
    return visit<std::string, int>(f, x);

但是,使用std::variant 更简单

void send_msg(std::variant<std::string, int> x)

    auto f = [](auto&& x)
        std::cout << x << '\n';
    ;
    visit(f, x);

†​​完整的visit 实现将是bit more complicated。

【讨论】:

以上是关于你能切换一个 std::any.type() 吗?的主要内容,如果未能解决你的问题,请参考以下文章

你能以编程方式在iOS 8(w / Swift)中切换“请勿打扰”模式吗?

SwiftUI 切换开关

Bootstrap 响应式菜单切换器的问题

为啥segues不起作用?无法切换视图

通过子组件在父组件中反应切换视图功能

asp.net中如何在Http和Https之间切换