C++ 中的 n={0,1,...,n-1}
n={0,1,...,n-1} in C++
自然数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)
^ ~~
但我认为我应该被允许这样做! :)
编辑:我知道我可以 "fake" 如果我在 for 循环中添加单词 "range" (或其他单词),但我我想知道是否可以不这样做。
您可以使用一些接近您想要的语法,但您需要一个包含要迭代的数字的数组。
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
做不到。来自 draft of the C++ 14 standard 的第 6.5.4 节(但 C++11 将非常相似)
begin-expr and end-expr are determined as follows:
(1.1) — if _RangeT
is an array type, [...];
嗯,这个显然不适用。 int
不是数组
(1.2) — if _RangeT is a class type, [...]
不,这也不适用。
(1.3) — otherwise, begin-expr and end-expr are begin(__range)
and end(__range)
, respectively,
哎呀!这看起来很有希望。您可能需要将 begin
和 end
移动到全局命名空间中,但仍然...
where begin
and end
are looked up in the associated namespaces (3.4.2). [ Note: Ordinary unqualified lookup (3.4.1)
is not performed. — end note ]
(强调我的)。烦!没有任何名称空间与 int
关联。具体来说,从第 3.4.2 节
— If T [int
in our case] is a fundamental type, its associated sets of namespaces and classes are both empty.
唯一的解决方法是编写一个 class range
,它具有合适的开始和结束方法。然后你可以写出非常 pythonic:
for (int i : range(5))
纯属娱乐...
您已将此问题标记为 C++14,因此您可以使用 std::integer_sequence
和 std::make_integer_sequence
。
如果自然数是已知的编译时间(如您的示例中的 10
),您可以编写一个简单的 constexpr
函数 getArray()
(使用辅助函数 getArrayH
) 得到从零到 N-1
的 std::array
个值
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;
}
如果您查看 the cppreference page for range-based for
loops, or better yet the relevant section of the standard ([stmt.ranged]p1),您会看到它如何确定要用于循环的 begin_expr
。 int
的相关项是
(1.3) otherwise, begin-expr and end-expr are begin(__range)
and end(__range)
, respectively, where begin and end are looked up in the associated namespaces ([basic.lookup.argdep]). [ Note: Ordinary unqualified lookup ([basic.lookup.unqual]) is not performed. — end note ]
(强调 添加)
不幸的是,对于用例,对于 int
等基本类型,依赖于参数的查找从来没有 returns 任何东西。
相反,你可以做的是声明一个 class 作为范围表达式,并给它 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);
}
};
对此 class 的潜在改进包括:
- 制作
begin
和 end
方法 constexpr
(这需要编写您自己的 boost::counting_iterator
版本,或者让 Boost 制作他们的版本 constexpr
)
- 添加用户定义的文字选项,如
Range operator""_range
- 使其适用于
unsigned int
以外的类型。
自然数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)
^ ~~
但我认为我应该被允许这样做! :)
编辑:我知道我可以 "fake" 如果我在 for 循环中添加单词 "range" (或其他单词),但我我想知道是否可以不这样做。
您可以使用一些接近您想要的语法,但您需要一个包含要迭代的数字的数组。
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
做不到。来自 draft of the C++ 14 standard 的第 6.5.4 节(但 C++11 将非常相似)
begin-expr and end-expr are determined as follows:
(1.1) — if _
RangeT
is an array type, [...];
嗯,这个显然不适用。 int
不是数组
(1.2) — if _RangeT is a class type, [...]
不,这也不适用。
(1.3) — otherwise, begin-expr and end-expr are
begin(__range)
andend(__range)
, respectively,
哎呀!这看起来很有希望。您可能需要将 begin
和 end
移动到全局命名空间中,但仍然...
where
begin
andend
are looked up in the associated namespaces (3.4.2). [ Note: Ordinary unqualified lookup (3.4.1) is not performed. — end note ]
(强调我的)。烦!没有任何名称空间与 int
关联。具体来说,从第 3.4.2 节
— If T [
int
in our case] is a fundamental type, its associated sets of namespaces and classes are both empty.
唯一的解决方法是编写一个 class range
,它具有合适的开始和结束方法。然后你可以写出非常 pythonic:
for (int i : range(5))
纯属娱乐...
您已将此问题标记为 C++14,因此您可以使用 std::integer_sequence
和 std::make_integer_sequence
。
如果自然数是已知的编译时间(如您的示例中的 10
),您可以编写一个简单的 constexpr
函数 getArray()
(使用辅助函数 getArrayH
) 得到从零到 N-1
std::array
个值
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;
}
如果您查看 the cppreference page for range-based for
loops, or better yet the relevant section of the standard ([stmt.ranged]p1),您会看到它如何确定要用于循环的 begin_expr
。 int
的相关项是
(1.3) otherwise, begin-expr and end-expr are
begin(__range)
andend(__range)
, respectively, where begin and end are looked up in the associated namespaces ([basic.lookup.argdep]). [ Note: Ordinary unqualified lookup ([basic.lookup.unqual]) is not performed. — end note ]
(强调 添加)
不幸的是,对于用例,对于 int
等基本类型,依赖于参数的查找从来没有 returns 任何东西。
相反,你可以做的是声明一个 class 作为范围表达式,并给它 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);
}
};
对此 class 的潜在改进包括:
- 制作
begin
和end
方法constexpr
(这需要编写您自己的boost::counting_iterator
版本,或者让 Boost 制作他们的版本constexpr
) - 添加用户定义的文字选项,如
Range operator""_range
- 使其适用于
unsigned int
以外的类型。