C++ 如何在C++;17岁的孩子?

C++ 如何在C++;17岁的孩子?,c++,c++11,for-loop,c++17,C++,C++11,For Loop,C++17,委员会将基于循环的范围从: C++11: { auto && __range = range_expression ; for (auto __begin = begin_expr, __end = end_expr; __begin != __end; ++__begin) { range_declaration = *__begin; loop_statement } } 对于C++17: {

委员会将基于循环的范围从:

  • C++11:

    {
       auto && __range = range_expression ; 
       for (auto __begin = begin_expr, __end = end_expr; 
           __begin != __end; ++__begin) { 
           range_declaration = *__begin; 
           loop_statement 
       }
    } 
    
  • 对于C++17:

    {        
        auto && __range = range_expression ; 
        auto __begin = begin_expr ;
        auto __end = end_expr ;
        for ( ; __begin != __end; ++__begin) { 
            range_declaration = *__begin; 
            loop_statement 
        } 
    }
    

人们说,这将使实施更容易。你能给我举几个例子吗

新规范允许
\uuu begin
\uu end
为不同类型,只要
\uu end
可以与
\uu begin
进行不平等性比较
\uu end
甚至不需要是迭代器,也可以是谓词。下面是一个愚蠢的示例,其中一个结构定义了
begin
end
成员,后者是谓词而不是迭代器:

#include <iostream>
#include <string>

// a struct to get the first word of a string

struct FirstWord {
    std::string data;

    // declare a predicate to make ' ' a string ender

    struct EndOfString {
        bool operator()(std::string::iterator it) { return (*it) != '\0' && (*it) != ' '; }
    };

    std::string::iterator begin() { return data.begin(); }
    EndOfString end() { return EndOfString(); }
};

// declare the comparison operator

bool operator!=(std::string::iterator it, FirstWord::EndOfString p) { return p(it); }

// test

int main() {
    for (auto c : {"Hello World !!!"})
        std::cout << c;
    std::cout << std::endl; // print "Hello World !!!"

    for (auto c : FirstWord{"Hello World !!!"}) // works with gcc with C++17 enabled
        std::cout << c;
    std::cout << std::endl; // print "Hello"
}
#包括
#包括
//获取字符串第一个单词的结构
结构首字{
std::字符串数据;
//声明一个谓词以使“”成为字符串结束符
结构内部字符串{
bool操作符()(std::string::iterator it){return(*it)!='\0'&&(*it)!='';}
};
std::string::iterator begin(){返回数据。begin();}
EndOfString end(){return EndOfString();}
};
//声明比较运算符
接线员=(std::string::iterator it,FirstWord::EndOfString p){返回p(it);}
//试验
int main(){
for(自动c:{“你好,世界!!!”})
std::cout C++11/14范围-
对于
是过度约束的。。。 这方面的WG21文件具有以下动机:

现有的基于范围的for循环过度约束。结束 迭代器从不递增、递减或取消引用。需要 它是一个迭代器,没有实际用途

正如您在发布的Standardese中所看到的,范围的
end
迭代器仅用于循环条件
\uuu begin!=\uu end;
。因此
end
只需要与
begin
相等,而不需要是可取消引用或可增加的

…对于分隔的迭代器,它会扭曲运算符==
。 那么这有什么缺点呢?好吧,如果你有一个哨兵分隔的范围(C字符串、文本行等),那么你必须把循环条件塞进迭代器的
操作符==
,基本上是这样的

#include <iostream>

template <char Delim = 0>
struct StringIterator
{
    char const* ptr = nullptr;   

    friend auto operator==(StringIterator lhs, StringIterator rhs) {
        return lhs.ptr ? (rhs.ptr || (*lhs.ptr == Delim)) : (!rhs.ptr || (*rhs.ptr == Delim));
    }

    friend auto operator!=(StringIterator lhs, StringIterator rhs) {
        return !(lhs == rhs);
    }

    auto& operator*()  {        return *ptr;  }
    auto& operator++() { ++ptr; return *this; }
};

template <char Delim = 0>
class StringRange
{
    StringIterator<Delim> it;
public:
    StringRange(char const* ptr) : it{ptr} {}
    auto begin() { return it;                      }
    auto end()   { return StringIterator<Delim>{}; }
};

int main()
{
    // "Hello World", no exclamation mark
    for (auto const& c : StringRange<'!'>{"Hello World!"})
        std::cout << c;
}
使用g++-std=c++1z(使用gcc.godbolt.org,这与前面的示例几乎相同)

…并且实际上将支持完全通用的原始“D样式”范围。 WG21文件有以下建议:

C.6系列外观和适配器实用程序[future.Facade]

1直到它 对于用户来说,创建自己的迭代器类型(完整的 迭代器的潜力仍然没有实现。范围抽象 使之成为可能。有了正确的库组件,它应该 用户可以使用最小的界面定义范围(例如。,
current
done
next
成员),并具有迭代器类型 自动生成。此范围facade类模板保留为 今后的工作

本质上,这等于D样式范围(其中这些原语被称为
empty
front
popFront
)。仅包含这些原语的分隔字符串范围如下所示:

template <char Delim = 0>
class PrimitiveStringRange
{
    char const* ptr;
public:    
    PrimitiveStringRange(char const* c) : ptr{c} {}
    auto& current()    { return *ptr;          }
    auto  done() const { return *ptr == Delim; }
    auto  next()       { ++ptr;                }
};
使用g++-std=c++1z(使用gcc.godbolt.org)


结论:Sentinel不仅仅是一种将分隔符压入类型系统的可爱机制,它们还具有足够的通用性(它们本身可能没有迭代器的概念)作为新的C++1z范围的零开销抽象。

我能看到的唯一区别是1.实现要求_begin和_end为同一类型。不需要第二次实现。是的。提案本身在动机中声明:现有的基于范围的for循环过度约束。结束迭代器是never递增、递减或取消引用。要求它是迭代器没有实际用途。放松基于范围的for循环的类型要求会给范围TS的用户提供最佳体验。我想知道最佳体验是什么样子。我想主要是为了支持代理端迭代器。范围允许或Sentinel作为结束标记(例如在以null结尾的字符串中),如果“开始”和“结束”都是迭代器,这是不可能的。是的。这是一个很好的例子,谢谢。但我试图找到一个范围TS的特定示例。@DimitarMirchev:范围TS实际上没有定义任何范围。它定义了许多作用于范围的算法,以及允许编写使用范围的代码的概念。但是Range TS v1没有提供任何实际的范围类型。因此没有可以提供的示例。@Nicolas为什么它与范围TS相关?我认为这是因为范围TS支持这些非对称迭代器/哨兵范围。@Yakk:是的,范围TS定义了允许迭代器/哨兵配对的范围概念。但它没有定义任何实际的范围使用它们的范围。因此,从范围TS中唯一可以显示的是一个概念。它简单地说“迭代器/哨兵配对是可以的”,这是我们已经知道的。它没有显示它们的使用示例。我在中给出了一个示例。另请参见。
template <char Delim = 0>
class PrimitiveStringRange
{
    char const* ptr;
public:    
    PrimitiveStringRange(char const* c) : ptr{c} {}
    auto& current()    { return *ptr;          }
    auto  done() const { return *ptr == Delim; }
    auto  next()       { ++ptr;                }
};
#include <iostream>

// adapt any primitive range with current/done/next to Iterator/Sentinel pair with begin/end
template <class Derived>
struct RangeAdaptor : private Derived
{      
    using Derived::Derived;

    struct Sentinel {};

    struct Iterator
    {
        Derived*  rng;

        friend auto operator==(Iterator it, Sentinel) { return it.rng->done(); }
        friend auto operator==(Sentinel, Iterator it) { return it.rng->done(); }

        friend auto operator!=(Iterator lhs, Sentinel rhs) { return !(lhs == rhs); }
        friend auto operator!=(Sentinel lhs, Iterator rhs) { return !(lhs == rhs); }

        auto& operator*()  {              return rng->current(); }
        auto& operator++() { rng->next(); return *this;          }
    };

    auto begin() { return Iterator{this}; }
    auto end()   { return Sentinel{};     }
};

int main()
{
    // "Hello World", no exclamation mark
    for (auto const& c : RangeAdaptor<PrimitiveStringRange<'!'>>{"Hello World!"})
        std::cout << c;
}