n={0,1,...,n-1}

问题描述 投票:0回答:4

自然数 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 循环中添加单词“范围”(或其他单词),我可以“伪造”它,但我想知道是否可以不这样做。

c++ c++14 set-theory
4个回答
10
投票

这是做不到的。 来自C++ 14 标准草案第 6.5.4 节(但 C++11 将非常相似)

begin-exprend-expr 确定如下:

(1.1) — 如果 _

RangeT
是数组类型,[...];

嗯,这显然不适用。

int
不是数组

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

不,这也不适用。

(1.3) — 否则,begin-exprend-expr 分别是

begin(__range)
end(__range)

哦! 这看起来很有希望。 您可能需要将

begin
end
移至全局命名空间,但仍然...

哪里

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

(强调我的)。 打扰! 没有任何与

int
关联的命名空间。 具体来说,来自第 3.4.2 节

— 如果 T [在我们的例子中为

int
] 是基本类型,则其关联的命名空间和类集都是空的。

唯一的解决方法是编写一个具有合适的开始和结束方法的类

range
。 然后你就可以写出非常Pythonic的代码了:

for (int i : range(5))

1
投票

如果您查看 基于范围的

for
循环的 cppreference 页面,或者更好的是标准的相关部分 ([stmt.ranged]p1),您会看到它如何确定 begin_expr
用于循环。与 
int
 相关的是 

(1.3) 否则,begin-exprend-expr 分别是 begin(__range)

end(__range)
,其中 begin 和 end 在关联的命名空间中查找 (
[basic.lookup.argdep] )。 [ 注意:不执行普通的不合格查找([basic.lookup.unqual])。 — 尾注 ]

强调已添加)

不幸的是,对于用例来说,对于诸如

int

之类的基本类型,依赖于参数的查找永远不会返回任何内容。

相反,您可以声明一个类作为范围表达式,并为其提供

begin

end
 方法:

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); } };
此类的潜在改进包括:

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

现场演示

那么你问题中的例子看起来像

for (int n : Range{10}) { std::cout << n << '\n'; }
您仍然无法直接使用 

int

,但您可以接近。


0
投票
只是为了好玩...

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

std::integer_sequence

std::make_integer_sequence

如果自然数在编译时已知(如示例中的

10

),您可以编写一个简单的
constexpr
函数
getArray()
(带有辅助函数
getArrayH
)来获取从零到值的
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; }
    

-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 equal to Python range() in C++/STL

© www.soinside.com 2019 - 2024. All rights reserved.