可以使用std :: any_cast有效地转换std :: any

时间:2019-12-18 09:45:54

标签: c++ templates casting c++17 std

我正在尝试在图书馆中使用std::any。我以cppreference.com为例,并以这种方式实现示例:

#include <any>
#include <iostream>

int main()
{
    struct example_1{
        int i1;
        int i2;
    };


    // any type
    std::any a = 1;
    std::cout << a.type().name() << ": " << std::any_cast<int>(a) << '\n';
    a = 3.14;
    std::cout << a.type().name() << ": " << std::any_cast<double>(a) << '\n';
    a = true;
    std::cout << a.type().name() << ": " << std::any_cast<bool>(a) << '\n';

    struct example_1 ex1;
    ex1.i1 = 1;
    ex1.i2 = 2;

    a = ex1;
    std::cout << a.type().name() << ": " << std::any_cast<struct example_1>(a).i1 << " ; " << std::any_cast<struct example_1>(a).i2 << '\n';

    // bad cast
    try
    {
        a = 1;
        std::cout << std::any_cast<float>(a) << '\n';
    }
    catch (const std::bad_any_cast& e)
    {
        std::cout << e.what() << '\n';
    }

    // has value
    a = 1;
    if (a.has_value())
    {
        std::cout << a.type().name() << '\n';
    }

    // reset
    a.reset();
    if (!a.has_value())
    {
        std::cout << "no value\n";
    }

    // pointer to contained data
    a = 1;
    int* i = std::any_cast<int>(&a);
    std::cout << *i << "\n";
}

输出如下:

i: 1
d: 3.14
b: 1
Z4mainE9example_1: 1 ; 2
bad any_cast
i
no value
1

在基本类型的情况下很容易,但是在结构的情况下,我们将调用std::any.type().name()作为结构的符号返回。

我认为将传递的std::any参数转换为正确的类型,如果包含子字符串“ structname”或“ classname”,我可以在符号字符串中进行搜索。但是我认为这只是一个解决方法。有没有一种方法可以有效地将std::any强制转换为正确的类型?

另一个问题,如果我在库中使用它,我将不知道所传递对象的结构或类的名称(因此,解决方法无法正常工作)。有没有办法检索它并使用正确类型的std::any_cast

2 个答案:

答案 0 :(得分:2)

.type().name()返回的值是完全由实现定义的,因此您无法以任何方式保证它们。您甚至无法保证.type().name()对于多种不同类型都是不相同的。

即使不是这种情况,.type().name()也会返回运行时值,并且您不能使用非恒定值来计算类型。

C ++是静态类型的。每个表达式(在模板实例化之后)都具有在编译时固定的类型。因此,在std::any不能(可能)知道其类型的情况下无法使用它。

您可以使用std::anyany_cast返回的std::type_info(通过它在{{之外)提供的其他成员,来获得.type()持有的类型和值。 1}}),只有当您在编译时确定了可以在代码位置(模板实例化之后)保存的一组可能类型的有限集合时,才可以。如果您不知道它在代码中给定位置(模板实例化之后)所具有的潜在类型,那么您将无法获得它在其中所具有的类型或值。

如果您的图书馆用户打算在.name()中使用他们的类型,而您实际上想在图书馆代码中提取值,那么您将需要对代码进行模板化,并且该用户需要提供潜在类型作为其模板参数。

在少数情况下,使用std::any是有意义的。通常std::any或虚拟基类接口(用户可以从中派生自己的类型)是合适的工具。或者,如果实际上不需要运行时多态性(我们不知道您的用例),只需编写用户可以提供其自定义类型的模板代码即可。


还应注意:在C ++中,在其类定义或显式前向声明之外的类型名称前请勿使用std::variant。这不是必需的,但是如果对类型的名称查找失败,可能会产生意想不到的后果。

答案 1 :(得分:0)

这是因为在编译过程中会进行优化。如果要在.show-read-more .more-text{ display: none; }上获取类型的全名,则必须<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <p>This is a paragraph.</p> <p>This is another paragraph.</p> <p class="show-read-more">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>的类型名(非标准)。

假设您在字符串变量runtime中包含类型名称:

demangle

请注意,您必须包括type_name才能调用int demangle_status; char* demangled_name = abi::__cxa_demangle(type_name.c_str(), nullptr, nullptr, &demangle_status; if (demangle_status == 0) { type_name = demangled_name; std::free(demangled_name) } std::cout << type_name