提问人:Daniel Tyebkhan 提问时间:8/20/2023 最后编辑:DailyLearnerDaniel Tyebkhan 更新时间:8/21/2023 访问量:118
std::optional<std::any> 和 has_value() 之间的交互
Interaction between std::optional<std::any> and has_value()
问:
出于调试目的,我正在编写一个函数,该函数遍历任何类型的可选变量的向量以检查哪些变量已初始化,但对所有变量的检查都返回,尽管从未为其中一些变量分配过任何值。has_value()
true
我将不胜感激任何帮助指出我的误解,因为我是C++的新手。代码如下。请注意,当注释行未注释时,if 语句会选取变量没有值。
#include <iostream>
#include <optional>
#include <any>
bool SimpleCheck(std::vector<std::optional<std::any>> toCheck)
{
bool res = false;
for (int i = 0; i < toCheck.size(); ++i)
{
// toCheck[i] = std::nullopt;
if (!toCheck[i].has_value())
{
std::cout << "item at index " << i << " had no value\n";
res = true;
}
}
return res;
}
int main()
{
std::optional<int> i = 5;
std::optional<std::string> str;
std::optional<double> doub = std::nullopt;
bool check = SimpleCheck({i, str, doub});
std::cout << check << "\n";
return 0;
}
我的预期输出是:
item at index 1 had no value item at index 2 had no value 1
实际输出为:
0
如果注释行未注释,则输出为:
item at index 0 had no value item at index 1 had no value item at index 2 had no value 1
答:
6赞
Jarod42
8/20/2023
#1
跟
std::optional<double> doub = std::nullopt;
std::optional<std::any> a = doub; // it is not a copy constructor
a
是非空的,但它是空的。any
std::optional
评论
0赞
Daniel Tyebkhan
8/20/2023
谢谢,这是有道理的。您(或其他任何人)是否知道正确进行此检查的方法,或者这是不可能的?我尝试恢复该值并检查它是否有值或将该值与 std::nullopt 进行比较,但这些都不起作用。
0赞
Jarod42
8/20/2023
是否要检查存储的是否为空?像这样:?optional
any
if (a) { if (auto* o = std::any_cast<std::optional<double>>(a.get())) { const bool b = o->has_value(); /*..*/ } }
0赞
Patrick Roberts
8/20/2023
@Jarod42不幸的是,这需要知道存储在什么专业化中只是为了检查它是否有价值。std::optional
std::any
0赞
Jarod42
8/20/2023
@PatrickRoberts:这是...... 将是一个替代方案,(所以你会有 /)。std::any
std::optional<std::any> i = 5;
std::any
int
string
0赞
Patrick Roberts
8/20/2023
我很想知道您是否/如何在这里强制选择 #4 而不是 #8......
3赞
Ted Lyngmo
8/20/2023
#2
所有 s 都包含 a,因此没有一个是空的。
此外,所有 s 都包含一个,因此它们都不是空的。std::optional<std::any>
std::any
std::any
std::optional<T>
如果要检查内部 s 是否包含值,则需要 to the 然后检查是否有值:optional
std::any_cast
std::any
optional<T>
template <class T>
bool test(const std::any& any) {
auto o = std::any_cast<T>(&any);
return o && o->has_value();
}
template <class... Ts>
bool has_optional_value(const std::any& any) {
return (... || test<std::optional<Ts>>(any));
}
bool SimpleCheck(std::vector<std::optional<std::any>> toCheck) {
bool res = false;
for(std::size_t i = 0; i < toCheck.size(); ++i) {
if (!(toCheck[i].has_value() &&
toCheck[i].value().has_value() &&
has_optional_value<int, std::string, double>(toCheck[i].value())))
{
std::cout << "item at index " << i << " had no value\n";
res = true;
}
}
return res;
}
输出:
item at index 1 had no value
item at index 2 had no value
1
1赞
Red.Wave
8/20/2023
#3
首先,效率不高。 确实也有方法。optional<any>
std::any
has_value
接下来,是 gready 并吞下所有喂食的东西,因此从中构造它不会检查可选然后检索值;它只是吞下 optional 并包含一个 optional。std::any
std::optional
解决您的问题的更好方法是我所说的 python 元组:
#include <any>
#include <array>
#include <ranges>
#include <format>
#include <vector>
#include <optional>
using py_tuple = std::vector<std::any>;
让我们使用一些C++20,23糖:
bool SimpleCheck(py_tuple toCheck)
{
bool res = false;
for( auto&& [i/*integer*/, x/*any&*/]
: toCheck
| std::views::enumerate )
{
if (x.has_value())
continue;
std::cout << std::format("item at index {} had no value\n");
res = true;
}
return res;
}
接下来我们需要一个变压器:
auto opt_to_any = []<typename T>
(std::optional<T> const& opt) -> std::any
{
if (opt.has_value()
return {opt.value()};//swallow
else
return {};//default construct
};
然后,我们使用您的输入调用测试:
bool check = SimpleCheck(
std::array{i, str, doub}
| std::views:: transform(opt_to_any)
| std::ranges::to<std::vector>() );
我懒得调用为 ;所以我最终链接了范围适配器以创建一个具有相同效果的更长的序列(我也很愚蠢)。opt_to_any
py_tuple
评论
std::any
可能用 ...std::optional<T>
std::any
std::optional
std::optional<std::any>