注意:这个问题被简单地标记为this的副本,但它不是完全相同的副本,因为我专门询问 std::optionals 。如果您关心一般情况,这仍然是一个值得阅读的好问题。
假设我有嵌套的选项,像这样(愚蠢的玩具示例):
struct Person{
const std::string first_name;
const std::optional<std::string> middle_name;
const std::string last_name;
};
struct Form{
std::optional<Person> person;
};
和这个垃圾邮件功能:
void PrintMiddleName(const std::optional<Form> form){
if (form.has_value() && form->person.has_value() && form->person->middle_name.has_value()) {
std::cout << *(*(*form).person).middle_name << std::endl;
} else {
std::cout << "<none>" << std::endl;
}
}
展平此可选检查的最佳方法是什么?我做了这样的东西,它不是可变参数,但我不太在意(membr3
如果真的有必要,我可以再添加一个级别(重载),除此之外的所有内容都是糟糕的代码)。
template<typename T, typename M>
auto flatten_opt(const std::optional<T> opt, M membr){
if (opt.has_value() && (opt.value().*membr).has_value()){
return std::optional{*((*opt).*membr)};
}
return decltype(std::optional{*((*opt).*membr)}){};
}
template<typename T, typename M1, typename M2>
auto ret_val_helper(){
// better code would use declval here since T might not be
// default constructible.
T t;
M1 m1;
M2 m2;
return ((t.*m1).value().*m2).value();
}
template<typename T, typename M1, typename M2>
std::optional<decltype(ret_val_helper<T, M1, M2>())> flatten_opt(const std::optional<T> opt, M1 membr1, M2 membr2){
if (opt.has_value() && (opt.value().*membr1).has_value()){
const auto& deref1 = *((*opt).*membr1);
if ((deref1.*membr2).has_value()) {
return std::optional{*(deref1.*membr2)};
}
}
return {};
}
void PrintMiddleName2(const std::optional<Form> form){
auto flat = flatten_opt(form, &Form::person, &Person::middle_name);
if (flat) {
std::cout << *flat;
}
else {
std::cout << "<none>" << std::endl;
}
}
笔记:
- 我不想切换
std::optional
到一些更好的可选. - 我不太关心性能,除非我返回一个我必须复制的指针(除非 arg 是临时的),因为
std::optional
不支持引用。 - 我不关心
flatten_has_value
函数(尽管它很有用),因为如果有一种方法可以很好地展平嵌套的可选项,那么还有一种方法可以编写该函数。 - 我知道我的代码看起来可以工作,但它很丑陋,所以我想知道是否有更好的解决方案。