4

这个答案中,我编写了 C++17 代码:

cout << accumulate(cbegin(numbers), cend(numbers), decay_t<decltype(numbers[0])>{});

这收到了一些关于 C++ 类型关联性质的负面评论,我很遗憾地说我同意:(

decay_t<decltype(numbers[0])>{}是一种非常复杂的方法来获得:

元素的零初始化类型numbers

是否可以保持与numbers' 元素类型的关联,但不能输入 30 个字符来获取它?

编辑:

我有很多答案都涉及到包装器accumulate或从numbers[0]. 问题是它们需要读者导航到次要位置以阅读与初始化代码一样复杂的解决方案decay_t<decltype(numbers[0])>{}

我们必须做更多的唯一原因是:decltype(numbers[0])因为数组下标运算符返回一个引用:

错误:将“int”类型的右值表达式无效转换为“int&”类型

有趣的是,关于decltype' 的论点:

如果对象的名称带括号,则将其视为普通的左值表达式

但是,decltype((numbers[0]))仍然只是对 的一个元素的引用numbers。所以最后这些答案可能与我们可以简化这个初始化一样接近:(

4

3 回答 3

2

个人偏好:我觉得decay_t, decltypeand declvaldance 很烦人,很难读懂。

value_t<It>相反,我会通过类型特征和零初始化使用额外的间接级别init = R{}

template<class It>
using value_t = typename std::iterator_traits<It>::value_type;

template<class It, class R = value_t<It>>
auto accumulate(It first, It last, R init = R{}) { /* as before */ }
于 2016-03-28T20:05:41.013 回答
2

虽然我总是会选择按照@Barry 编写一个辅助函数,但如果 numbers 是标准容器,它将导出 value_type 类型,因此您可以节省一点复杂性:

cout << accumulate(cbegin(numbers), cend(numbers), decltype(numbers)::value_type());

更进一步,我们可以定义这个模板函数:

template<class Container, class ElementType = typename Container::value_type>
constexpr auto element_of(const Container&, ElementType v = 0)
{
    return v;
}

这给了我们这个:

cout << accumulate(cbegin(numbers), cend(numbers), element_of(numbers, 0));
于 2016-03-28T18:19:05.353 回答
1

我认为您能做的最好的事情就是在某个地方考虑​​一下:

template <class It, class R = std::decay_t<decltype(*std::declval<It>())>>
R accumulate(It first, It last, R init = 0) {
    return std::accumulate(first, last, init);
}

std::cout << accumulate(cbegin(numbers), cend(numbers));

或更一般地说:

template <class Range, class T =
        std::decay_t<decltype(*adl_begin(std::declval<Range&&>()))>>
T accumulate(Range&& range, T init = 0) {
    return std::accumulate(adl_begin(range), adl_end(range), init);
}

cout << accumulate(numbers);

ADL 帐户adl_begin的版本在哪里。begin()

当然,从技术上讲,我们仍然拥有您之前试图避免的所有麻烦……但至少现在您不必再看一遍了?

于 2016-03-28T18:13:23.773 回答