问题描述
我有一些输入,可以是简单的值或容器,封装在 std::any
中。我不想使用异常,所以我调用 noexcept
可变参数 any_cast
方法,该方法返回指向 any 值的指针或 nullptr
。
我可以使用 typeid()
验证任何可用的演员表,但我不想使用它并想找到一些替代方法。一些 typetraits 方法,例如 decltype
、declval
等。或者简单地使用 std::optional
。
但在这种情况下,可选似乎仍然潮湿和不稳定。 MSVC 编译器程序在运行时在 std::optional
源代码的深处中断。
#include <optional>
#include <any>
#include <utility>
int main() {
int input = 1;
std::initializer_list<int> input2;
input2 = {1,2,3};
std::any any1 = input;
std::any any2 = input2;
std::optional o1 = *std::any_cast<int>(&any1);
std::optional p2 = *std::any_cast<int>(&any2);
// **std::forward<int & __ptr64>**(...) in _Optional_destruct_base return nullptr.
}
实际上,typetraits 检查将是测试 any_cast
可能性的最佳方式。但我仍然对 C++ 元编程感到困惑。
解决方法
永远不要在不知道指针非空的情况下取消引用它。
这通常适用于所有可空类型;在 C++ 中,这些通常是支持一元 *
和 ->
的类型。
std::optional o1 = std::any_cast<int>(&any1)?*std::any_cast<int>(&any1):std::optional<int>();
例如。
任何对可空类型的取消引用都是 UB,就 C++ 标准而言,它可以工作、崩溃或做任何其他事情。
但如果您的存储类型集是关闭的(不改变),也要考虑 std 变体。
,如果您想坚持使用 std::optional
并且不想使用指针,我认为您可以编写自己的函数来为您执行指针检查并返回正确的 std::optional
,例如:
template <typename T>
std::optional<T> get_v_opt(const std::any & a)
{
if(const T * v = std::any_cast<T>(&a))
return std::optional<T>(*v);
else
return std::nullopt;
}
这里是如何使用这样一个函数的用法示例:
int main()
{
std::any a(42);
std::optional opt_int = get_v_opt<int>(a);
std::optional opt_str = get_v_opt<std::string>(a);
if(opt_int.has_value())
std::cout << "a is an int with value: " << opt_int.value() << '\n';
else
std::cout << "a is not an int\n";
if(opt_str.has_value())
std::cout << "a is a string with value: " << opt_str.value() << '\n';
else
std::cout << "a is not a string\n";
return 0;
}
输出(对于这个例子):
a 是一个 int 值:42
a 不是字符串