• 14.3. Boost.Any

    14.3. Boost.Any

    像 C++ 这样的强类型语言要求给每个变量一个确定的类型。 而以 JavaScript 为代表的弱类型语言却不这样做, 弱类型的每个变量都可以存储数组、 布尔值、 或者是字符串。

    库 Boost.Any 给我们提供了 boost::any 类, 让我们可以在 C++ 中像 JavaScript 一样的使用弱类型的变量。

    1. #include <boost/any.hpp>
    2.  
    3. int main()
    4. {
    5. boost::any a = 1;
    6. a = 3.14;
    7. a = true;
    8. }
    • 下载源代码

    为了使用 boost::any, 你必须要包含头文件: boost/any.hpp。 接下来, 你就可以定义和使用 boost::any 的对象了。

    需要注明的是: boost::any 并不能真的存储任意类型的值; Boost.Any 需要一些特定的前提条件才能工作。 任何想要存储在 boost::any 中的值,都必须是可拷贝构造的。 因此,想要在 boost::any 存储一个字符串类型的值, 就必须要用到 std::string , 就像在下面那个例子中做的一样。

    1. #include <boost/any.hpp>
    2. #include <string>
    3.  
    4. int main()
    5. {
    6. boost::any a = 1;
    7. a = 3.14;
    8. a = true;
    9. a = std::string("Hello, world!");
    10. }
    • 下载源代码

    如果你企图把字符串 "Hello, world!" 直接赋给 a , 你的编译器就会报错, 因为由基类型 char 构成的字符串在 C++ 中并不是可拷贝构造的。

    想要访问 boost::any 中具体的内容, 你必须要使用转型操作: boost::any_cast

    1. #include <boost/any.hpp>
    2. #include <iostream>
    3.  
    4. int main()
    5. {
    6. boost::any a = 1;
    7. std::cout << boost::any_cast<int>(a) << std::endl;
    8. a = 3.14;
    9. std::cout << boost::any_cast<double>(a) << std::endl;
    10. a = true;
    11. std::cout << boost::any_cast<bool>(a) << std::endl;
    12. }
    • 下载源代码

    通过由模板参数传入 boost::any_cast 的值, 变量会被转化成相应的类型。 一旦你指定了一种非法的类型, 该操作会抛出 boost::bad_any_cast 类型的异常。

    1. #include <boost/any.hpp>
    2. #include <iostream>
    3.  
    4. int main()
    5. {
    6. try
    7. {
    8. boost::any a = 1;
    9. std::cout << boost::any_cast<float>(a) << std::endl;
    10. }
    11. catch (boost::bad_any_cast &e)
    12. {
    13. std::cerr << e.what() << std::endl;
    14. }
    15. }
    • 下载源代码

    上面的例子就抛出了一个异常, 因为 float 并不能匹配原本存储在 a 中的 int 类型。 记住, 在任何情况下都保证 boost::any 中的类型匹配是很重要的。 在没有通过模板参数指定 shortlong 类型时, 同样会有异常抛出。

    既然 boost::bad_any_cast 继承自 std::bad_castcatch 当然也可以捕获相应类型的异常。

    想要检查 boost::any 是否为空, 你可以使用 empty() 函数。 想要确定其中具体的类型信息, 你可以使用 type() 函数。

    1. #include <boost/any.hpp>
    2. #include <typeinfo>
    3. #include <iostream>
    4.  
    5. int main()
    6. {
    7. boost::any a = 1;
    8. if (!a.empty())
    9. {
    10. const std::type_info &ti = a.type();
    11. std::cout << ti.name() << std::endl;
    12. }
    13. }
    • 下载源代码

    上面的例子同时用到了 empty()type() 函数。 empty() 将会返回一个布尔值, 而 type() 则会返回一个在 typeinfo 中定义的 std::type_info 值。

    作为对这一节的总结, 最后一个例子会向你展示怎样用 boost::any_cast 来定义一个指向 boost::any 中内容的指针。

    1. #include <boost/any.hpp>
    2. #include <iostream>
    3.  
    4. int main()
    5. {
    6. boost::any a = 1;
    7. int *i = boost::any_cast<int>(&a);
    8. std::cout << *i << std::endl;
    9. }
    • 下载源代码

    你需要做的就是传递一个 boost::any 类型的指针, 作为 boost::any_cast 的参数; 模板参数却没有任何改动。