在C ++中n = {0,1,...,n-1}

时间:2017-10-30 16:42:16

标签: c++ c++14 set-theory

自然数n的形式定义(在集合论中)如下:

  • 0是空集
  • 1 = {0}
  • n = {0,1,...,n-1}

我认为这会使一些C ++代码更简单,如果我被允许这样做:

for (int n : 10)
    cout << n << endl;

并打印0到9之间的数字。

所以我尝试执行以下操作,但不编译:

#include <iostream>
#include <boost/iterator/counting_iterator.hpp>


    boost::counting_iterator<int> begin(int t)
    {
        return boost::counting_iterator<int>(0);
    }

    boost::counting_iterator<int> end(int t)
    {
        return boost::counting_iterator<int>(t);
    }



int main() 
{
    for (int t : 10)
        std::cout << t << std::endl;

    return 0;
}

有关如何实现这一目标的任何建议?我用clang ++得到以下错误:

main.cpp:22:20: error: invalid range expression of type 'int'; no viable 'begin' function available
        for (int t : 10)
                ^ ~~

但我想我应该被允许这样做! :)

编辑:我知道如果我在for循环中添加“range”(或其他一些单词),我可以“伪造”它,但我想知道是否可以这样做不

4 个答案:

答案 0 :(得分:10)

无法做到。从draft of the C++ 14 standard的6.5.4节(但C ++ 11将非常相似)

  

begin-expr end-expr 的确定如下:

     

(1.1) - 如果_ RangeT是数组类型,[...];

嗯,这个显然不适用。 int不是数组

  

(1.2) - 如果_RangeT是类类型,[...]

不,这也不适用。

  

(1.3) - 否则, begin-expr end-expr 分别为begin(__range)end(__range)

乌!这看起来很有希望。您可能需要将beginend移动到全局命名空间中,但仍然......

  

其中begin   在关联的命名空间中查找end(3.4.2)。 [注意:普通不合格查询(3.4.1)   没有执行。 - 尾注]

(强调我的)。烦!没有与int关联的任何名称空间。具体来说,请参见第3.4.2节

  

- 如果我们的T [int]是基本类型,则其关联的命名空间和类集都是空的。

唯一的工作是编写一个具有合适的begin和end方法的类range。然后你可以写出非常pythonic:

for (int i : range(5))

答案 1 :(得分:1)

如果您查看the cppreference page for range-based for loops,或者更好的标准相关部分([stmt.ranged]p1),您会看到它如何确定要使用的 begin_expr 为循环。 int的相关内容是

  

(1.3)否则, begin-expr end-expr 分别为begin(__range)end(__range),其中start和end在相关的命名空间([basic.lookup.argdep])中查找。 [注意:不执行普通的非限定查找([basic.lookup.unqual])。 - 结束记录]

强调添加)

不幸的是,对于用例,对于基本类型,例如int,依赖于参数的查找永远不会返回任何内容。

相反,您可以做的是声明一个类作为范围表达式,并为其提供beginend方法:

struct Range {
    using value_type = unsigned int;
    using iterator = boost::counting_iterator<value_type>;

    unsigned int max;

    iterator begin() const
    {
        return iterator(0);
    }

    iterator end() const
    {
        return iterator(max);
    }
};

此课程的潜在改进包括:

  • 制作beginend方法constexpr(这需要编写您自己的boost::counting_iterator版本,或者让Boost制作他们的版本constexpr)< / LI>
  • 添加用户定义的文字选项,例如Range operator""_range
  • 使其适用于unsigned int以外的其他类型。

live demo

答案 2 :(得分:0)

只是为了好玩......

您已将此问题标记为C ++ 14,因此您可以使用std::integer_sequencestd::make_integer_sequence

如果自然数是已知编译时间(在示例中为10),则可以编写一个简单的constexpr函数getArray()(带辅助函数getArrayH)从{0到std::array

获取N-1个值
template <typename T, T ... Vals>
constexpr std::array<T, sizeof...(Vals)>
   getArrayH (std::integer_sequence<T, Vals...> const &)
 { return { { Vals... } }; }

template <typename T, T Val>
constexpr auto getArray ()
 { return getArrayH(std::make_integer_sequence<T, Val>{}); }

并将其命名为

for ( auto const & i : getArray<int, 10>() )

以下是一个完整的工作示例

#include <array>
#include <utility>
#include <iostream>

template <typename T, T ... Vals>
constexpr std::array<T, sizeof...(Vals)>
   getArrayH (std::integer_sequence<T, Vals...> const &)
 { return { { Vals... } }; }

template <typename T, T Val>
constexpr auto getArray ()
 { return getArrayH(std::make_integer_sequence<T, Val>{}); }

int main ()
 {
   for ( auto const & i : getArray<int, 10>() )
      std::cout << i << std::endl;
 }

答案 3 :(得分:-1)

您可以使用一些接近您想要的语法,但是您需要一个数组,其中包含您想要迭代的数字。

int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for (int n : a)
    std::cout << n << std::endl;

http://en.cppreference.com/w/cpp/language/range-for

修改:要创建数组而不声明每个值,您可以检查此问题:Is there a compact equivalent to Python range() in C++/STL