在C++数组中检测数据类型

3
这是打印出填充有0、1、2……254的buf数组的c++代码。
#include <iterator>
#include <iostream>
#include <numeric>

int main()
{
        int buf[255];

        auto it_b = std::begin(buf);
        auto it_e = std::end(buf);

        std::iota(it_b, it_e, 0);
        std::copy(it_b, it_e, std::ostream_iterator<decltype(*it_b)>(std::cout, " "));

        std::cout << std::endl;

        return 0;
}

我试图让它通用,所以只有一个明确给出类型int的地方。

由于我需要明确声明ostream_iterator的类型,我想知道实现这一点的最佳方法是什么。

  1. decltype(*it_b)
  2. decltype(buf[0])
  3. 其他方法...

使用这种或那种方法的利弊是什么?

假设我们此时被困在C风格数组中。


4
为避免使用引用,可以使用std::decay_t<declval(..)> - Jarod42
1
使用 type = int;,并在问号后使用 type - Jarod42
2个回答

7

严格来说,您应该使用 std::iterator_traits

std::copy(it_b, it_e, std::ostream_iterator<
    typename std::iterator_traits<decltype(it_b)>::value_type
>(std::cout, " "));

decltype(*it_b) 单独使用的一个问题是,它在大多数情况下会返回一个引用,这会影响到您正在实例化的外部模板。您也可以手动去掉引用:

std::copy(it_b, it_e, std::ostream_iterator<
    std::remove_reference_t<decltype(*it_b)>
>(std::cout, " "));

为什么不使用decay_t?那样也会移除任何cv限定符,但我们这里不需要,我猜。 - leemes
2
@leemes 这取决于情况。std::decay_t 模拟将其参数传递给函数,因此它执行了许多可能相关或不相关的操作。最可靠的选项仍然是 iterator_traits - Quentin

4

也许这两个选项都不是你想要的 - 在这两种情况下,你最终得到的是你的类型的lvalue引用,即int&。你可以通过使用std::decay来避免它,例如:

std::copy(it_b, it_e, std::ostream_iterator<std::decay_t<decltype(*it_b)>>(std::cout, " "));

最简单的方法是保持类型别名并使用该别名:
using type = int;
type buf[255];

auto it_b = std::begin(buf);
auto it_e = std::end(buf);

std::iota(it_b, it_e, 0);
std::copy(it_b, it_e, std::ostream_iterator<type>(std::cout, " "));

std::cout << std::endl;

这也适用于像 vector<bool> 这样的病态容器,其中推断类型可能会导致令人惊讶(和未定义的)行为。


vector<bool> 以何种方式是一个容器? ;) - Yakk - Adam Nevraumont
我知道夸大事实会让我吃亏 ;) 不过,说实话,vector<bool>是*[容器]*的一部分,并且确实满足大多数要求。 - krzaq

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接