2016-01-27 48 views
1

假设我有一个函数可以查找并返回矢量的最小元素。如果向量是空的,它应该返回一个空的可选对象。有没有办法让我使用optional<T>构造函数来避免使用if语句或三元运算符?如何在没有if语句的情况下返回可选的<T>?

随着if语句:

optional<Foo> GetMinElement(vector<Foo> foos) { 
    vector<Foo>::iterator min_foo = std::min_element(foos.begin(), foos.end()); 
    bool found_min_element = (min_foo != foos.end()); 
    if (found_min_element) { 
    return *min_foo; 
    } else { 
    return nullopt; 
    } 
} 

随着三元运算符:

optional<Foo> GetMinElement(vector<Foo> foos) { 
    vector<Foo>::iterator min_foo = std::min_element(foos.begin(), foos.end()); 
    bool found_min_element = (min_foo != foos.end()); 
    return found_min_element ? optional<Foo>(*min_foo) : optional<Foo>(nullopt); 
} 

天真,我只是希望能够给stl算法的输出传递到optional<T>构造和有它处理检查空指针的逻辑。有没有一些成语呢?

+4

单看迭代器就不能确定它是否可解引用。这本身是必要的,但并不足够:算法可能已被调用超过'(someContainer.begin(),someContainer.end())'范围以外的范围。鉴于此,不涉及调用代码明确检查“找到算法的算法”的解决方案似乎不太可能。 –

回答

2

你要记住,结束迭代是不是一个空指针。如果范围是子范围,它甚至可以是有效的迭代器。

我写我自己的范围算法。他们遵循与你不同的模式。

范围算法需要class Range,启用adl启用begin/end并运行迭代器算法。然后它返回一个可选迭代器(如果它是end,则为空)。

这与你的略有不同,因为我不会返回元素的副本。

它们可以在任何地方使用(加上make_range(start,finish))。


如果你不喜欢,如果和?两者的语法,这些可能会有帮助:

template<class T> 
std::optional<std::decay_t<T>> maybe(bool engage, T&&t){ 
    if (!engage) return {}; 
    return std::forward<T>(t); 
} 

甚至:

templace<class F> 
std::optional<std::decay_t<std::result_of_t<F()>>> 
perhaps(bool do_it, F&&f){ 
    if (!engage) return {}; 
    return std::forward<F>(f)(); 
} 

,类似的?短路一样。

namespace adl_helper{ 
    using std::begin; using std::end; 
    template<class R> auto adl_begin(R&&)->decltype(begin(std::declval<R>())){ 
    return begin(std::forward<R>(r)); 
    } 
    template<class R> auto adl_end(R&&)->decltype(end(std::declval<R>())){ 
    return end(std::forward<R>(r)); 
    } 
} 
using adl_helper::adl_begin; 
using adl_helper::adl_end; 

template<class R>using iterator_t=decltype(adl_begin(std::declval<R>())); 

template<class R> 
optional<iterator_t<R>> min_element(R&& r) { 
    auto ret = std::min_element(adl_begin(r), adl_end(r)); 
    return maybe(ret!=adl_end(r), ret); 
} 

我发现它比你的版本更有用。

有时您需要额外做*或者使用帮手。

2

optional似乎没有一个构造函数,有时可以产生一个空的可选和sumetimes产生完整的。

也许你可以做一个帮手:

template<typename Iter> 
optional<typename Iter::value_type> try_deref(Iter pos, Iter singular) 
{ 
    if (pos != singular) 
     return *pos; 

    return {}; 
} 

使用范例:

optional<Foo> GetMinElement(std::vector<Foo> const &foos) 
{ 
    auto min_foo = std::min_element(foos.begin(), foos.end()); 
    return try_deref(min_foo, foos.end()); 
} 
+1

或者,helper可以接受'pos'和一个布尔值,用法是'bla(min_foo,min_foo == foos.end())' –

相关问题