1

関連:各範囲タイプのテンプレートの特殊化

バックグラウンド

C++11 では、範囲ベースの for ループは、こちら (リンク) で概説されている 3 種類の「範囲」を処理します。以下、該当部分を引用しました。

構文

for (range_declaration : range_expression) loop_statement

説明

上記の構文は、次のようなコードを生成します ( __range__beginおよび__end説明のみを目的としています)。

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

が評価され、range_expression反復されるシーケンスまたは範囲が決定されます。シーケンスの各要素は逆参照され、 で指定された型と名前を使用して変数に割り当てられますrange_declaration

begin_exprとは、次のend_exprいずれかになるように定義されています。

  • (__range)が配列の場合、(__range)および(__range + __bound)、ここで__boundはバインドされた配列です。
  • (__range)がクラスで、begin または end メンバー (または両方) を持つ場合、begin_expris__range.begin()およびend_expris __range.end();
  • それ以外の場合、begin(__range)およびは、関連付けられた名前空間としてend(__range)引数依存のルックアップ ルールに基づいて検出されます。std

質問

の型が与えられた場合、範囲ベースの for ループが使用するイテレータの型を取得するために何かを書くにはどうすればよいrange_expressionですか? std::iterator_traits<Iterator>::value_type(の型が指定されたイテレータ値の型を取得する方法に似ていますIterator。)

range_traits<Range>::iterator_type特定の範囲型を記述Rangeし、それを範囲ベースの for ループが使用するイテレータの型にしたいと考えています。

私はこれを試しました:

template <typename Range>
struct range_traits
{
    //Try to use ADL to get correct "begin" function, or std::begin by default
    using std::begin;
    typedef typename decltype(begin(std::declval<Range>())) iterator_type;
};

usingただし、クラス本体の using 宣言のコンテキストでは、宣言は基底クラスのメンバーを宣言するためのものであるため、これは機能しません。

以下using std::begin、私が望むことを行うため、機能します( std::beginADLが失敗した場合はデフォルトになります)。

template <typename Range>
void example(Range& range)
{
    using std::begin;
    auto it = begin(range); //it is of the type I want
    //the expression decltype(begin(range)) would get the type I want
}

問題は、関数本体から型を実際に取得できないことです。

このタスクを達成する方法についてのアイデアはありますか? 使用できる SFINAE 魔法はありますか? 何を達成しようとしているのかが明確でない場合は、より明確にしようとします。

4

1 に答える 1

1

これはうまくいったようです:

#include <iterator>

namespace range_trait_namespace {
  using std::begin;
  template<typename Range>struct range_traits {
    typedef decltype(begin(std::declval<Range>())) iterator_type;
  };
}


#include <iostream>
#include <vector>

int main(int, char**) {
  std::cout << "oi\n";
  std::vector<int> i { 1, 2, 3, };
  for( auto x: i )
    std::cout << x << "\n";
  for( range_trait_namespace::range_traits<std::vector<int>>::iterator_type aa = i.begin(); aa != i.end(); ++aa)
    std::cout << *aa << "\n";
  return 0;
}
于 2013-06-19T00:56:54.940 に答える