如何在编译时捕获 std::variant 持有错误类型?

Posted

技术标签:

【中文标题】如何在编译时捕获 std::variant 持有错误类型?【英文标题】:How to catch std::variant holding wrong type in compile-time? 【发布时间】:2021-09-09 16:11:44 【问题描述】:

我有以下代码:

#include <iostream>
#include <string>
#include <map>
#include <variant>

using namespace std;

template <class... Ts>
struct overloaded : Ts...

    using Ts::operator()...;
;
template <class... Ts>
overloaded(Ts...)->overloaded<Ts...>;

using element_dict = std::map<string, string>;
using element_type = std::variant<string, element_dict, int>;

void foo(element_type elements)

    std::visit(overloaded
            [](string element)  cout << "string\n"; ,
            [](element_dict element)  cout << "dict\n";,
            [](auto /*elements*/)  throw std::runtime_error("wrong type"); 
        , elements);


int main()

    element_type str_elems = "string_elem";
    foo(str_elems);
    element_type dict_elems = element_dict "string", "string" ;
    foo(dict_elems);
    element_type wrong_type_elems = 5;
    foo(wrong_type_elems); // throws error

    return 0;

标准输出:

string
dict
libc++abi.dylib: terminating with uncaught exception of type std::runtime_error: wrong type

我有 element_type 包含几种类型。基本上我认为它包含stringelement_dict。在这里我遇到有人将int 类型添加到element_type,但忘记为foo 函数提供所需修复的情况。现在我在运行时抛出异常中检测到这种情况。有没有办法在编译时检测到它?

【问题讨论】:

是的。删除[](auto /*elements*/) 过载。该重载将编译时错误“转换”为运行时异常。 你为什么认为你需要第三次重载? 【参考方案1】:

让这种情况在编译时失败的最简单方法是不包含捕获非string 和非element_dict 类型项的重载 lambda;也就是去掉

[](auto /*elements*/)  throw std::runtime_error("wrong type"); 

然后它将在编译时失败。基本上,通过包含该案例,您明确告诉编译器您希望它成功编译此类案例;你选择加入你不想要的行为。

【讨论】:

以上是关于如何在编译时捕获 std::variant 持有错误类型?的主要内容,如果未能解决你的问题,请参考以下文章

使用类作为数据类型时如何在 std::variant 中存储值?

如何将 std::variant 作为 VARIANT* 传递给 ExecWB?

在构造 std::variant 时禁用从指针类型到 bool 的隐式转换的最佳方法是啥?

如何将 boost::hana::tuple 转换为 std::variant

如何访问`std::variant`的任何孩子的`polymorphic`基类?

如何将 std::variant 与非平凡的用户对象(稍后构建)一起使用,并让访问者使用自动 lambda?