質問(およびほとんどの回答)がこの欠陥レポートの解決策に掲載されて以来、標準は変更されています。
for(:)
型でループを機能させるX
方法は、次の2つの方法のいずれかになります。
const
バリエーションについても同様です。これは、欠陥レポートの変更を実装するコンパイラと実装しないコンパイラの両方で機能します。
返されるオブジェクトは、実際にイテレータである必要はありません。for(:)
ループは、C ++標準の大部分とは異なり、されに何か相当に拡大して指定します:
for( range_declaration : range_expression )
になる:
{
auto && __range = range_expression ;
for (auto __begin = begin_expr,
__end = end_expr;
__begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
ここで始まる変数__
は説明のためだけでありbegin_expr
、/. ² end_expr
を呼び出す魔法ですbegin
end
begin / endの戻り値の要件は単純です。pre-をオーバーロードし++
、初期化式が有効で!=
あること、ブールコンテキストで使用できるバイナリ、*
割り当て初期化できるものを返す単項range_declaration
、およびパブリックを公開する必要があります。デストラクタ。
イテレータと互換性のない方法でこれを行うことは、おそらく悪い考えです。C++の将来の反復は、コードを壊すことに関して比較的無頓着になる可能性があるためです。
余談ですが、標準の将来の改訂では、とend_expr
は異なるタイプを返すことが許可される可能性がかなりありbegin_expr
ます。これは、手書きのCループと同じくらい効率的に最適化するのが簡単な「遅延終了」評価(ヌル終了の検出など)を許可するという点で役立ちます。
loop for(:)
ループは一時auto&&
変数を変数に格納し、それを左辺値として渡すことに注意してください。一時(または他の右辺値)を反復処理しているかどうかは検出できません。このようなオーバーロードはfor(:)
ループによって呼び出されません。n4527の[stmt.ranged] 1.2-1.3を参照してください。
²呼び出しのどちらかbegin
/のend
方法を、またはADL専用のルックアップフリー機能のbegin
/ end
、または Cスタイルの配列をサポートするための魔法。タイプが同じまたは依存しているオブジェクトを返さstd::begin
ない限り、は呼び出されないことに注意してください。range_expression
namespace std
に c ++ 17 range-for式が更新されました
{
auto && __range = range_expression ;
auto __begin = begin_expr;
auto __end = end_expr;
for (;__begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
__begin
およびのタイプで__end
分離されています。
これにより、終了反復子がbeginと同じ型にならないようにすることができます。終了反復子タイプは!=
、開始反復子タイプでのみサポートされる「センチネル」にすることができます。
これは便利である理由の実用的な例は、反復子は、「あなたをチェック読むことができるあなたの最後ということでchar*
、それが指すかどうかを確認するために'0'
とき」==
とchar*
。これにより、C ++のrange-for式は、nullで終了するchar*
バッファーを反復処理するときに最適なコードを生成できます。
struct null_sentinal_t {
template<class Rhs,
std::enable_if_t<!std::is_same<Rhs, null_sentinal_t>{},int> =0
>
friend bool operator==(Rhs const& ptr, null_sentinal_t) {
return !*ptr;
}
template<class Rhs,
std::enable_if_t<!std::is_same<Rhs, null_sentinal_t>{},int> =0
>
friend bool operator!=(Rhs const& ptr, null_sentinal_t) {
return !(ptr==null_sentinal_t{});
}
template<class Lhs,
std::enable_if_t<!std::is_same<Lhs, null_sentinal_t>{},int> =0
>
friend bool operator==(null_sentinal_t, Lhs const& ptr) {
return !*ptr;
}
template<class Lhs,
std::enable_if_t<!std::is_same<Lhs, null_sentinal_t>{},int> =0
>
friend bool operator!=(null_sentinal_t, Lhs const& ptr) {
return !(null_sentinal_t{}==ptr);
}
friend bool operator==(null_sentinal_t, null_sentinal_t) {
return true;
}
friend bool operator!=(null_sentinal_t, null_sentinal_t) {
return false;
}
};
C ++ 17を完全にサポートしていないコンパイラでのライブの例。for
ループは手動で拡張されました。
begin/end
、静的または無料のメンバーまたは友達を定義することによって可能begin/end
です。:ちょうどあなたがフリー機能置かれた名前空間に注意してくださいstackoverflow.com/questions/28242073/...