任意の変数型が反復可能かどうかを確認する方法はありますか?
インデックス付きの要素があるかどうかを確認するには、実際にその子のループをループできますか? (たとえば foreach を使用しますか?)
そのためのユニバーサルテンプレートを作成することは可能ですか?
検索中に他のプログラミング言語のテクニックを見つけました。それでも、C++ でこれを行う方法を見つける必要があります。
任意の変数型が反復可能かどうかを確認する方法はありますか?
インデックス付きの要素があるかどうかを確認するには、実際にその子のループをループできますか? (たとえば foreach を使用しますか?)
そのためのユニバーサルテンプレートを作成することは可能ですか?
検索中に他のプログラミング言語のテクニックを見つけました。それでも、C++ でこれを行う方法を見つける必要があります。
そのための特性を作成できます。
namespace detail
{
// To allow ADL with custom begin/end
using std::begin;
using std::end;
template <typename T>
auto is_iterable_impl(int)
-> decltype (
begin(std::declval<T&>()) != end(std::declval<T&>()), // begin/end and operator !=
void(), // Handle evil operator ,
++std::declval<decltype(begin(std::declval<T&>()))&>(), // operator ++
void(*begin(std::declval<T&>())), // operator*
std::true_type{});
template <typename T>
std::false_type is_iterable_impl(...);
}
template <typename T>
using is_iterable = decltype(detail::is_iterable_impl<T>(0));
実例。
「反復可能」の意味によって異なります。イテレータはさまざまな方法で実装できるため、C++ ではあいまいな概念です。
foreach
C++11 の範囲ベースの for ループについて言及している場合は、型begin()
とメソッドを定義し、 、 、
およびend()
に応答する反復子を返す必要があります。operator!=
operator++
operator*
Boost の BOOST_FOREACH ヘルパーを意味する場合は、BOOST_FOREACH Extensibilityを参照してください。
設計に、反復可能なすべてのコンテナーが継承する共通のインターフェイスがある場合、C++11 のstd::is_base_ofを使用できます。
struct A : IterableInterface {}
struct B {}
template <typename T>
constexpr bool is_iterable() {
return std::is_base_of<IterableInterface, T>::value;
}
is_iterable<A>(); // true
is_iterable<B>(); // false
または、(私のように)すべての SFINAE ソリューションがダミーの構造体定義の大きなブロックであり::type
、::value
無意味であることが嫌いな場合は、すばやく(非常に)汚いワンライナーを使用する例を次に示します。
template <
class Container,
typename ValueType = decltype(*std::begin(std::declval<Container>()))>
static void foo(Container& container)
{
for (ValueType& item : container)
{
...
}
}
最後のテンプレート引数は、1 つのステップで複数のことを行います。
begin()
メンバー関数または同等のものがあるかどうかを確認します。begin()
が定義済みのものを返すことを確認しますoperator*()
(イテレータの場合に典型的)。end()
制限: 一致するメンバー関数があることを再確認しません。
より堅牢で完全な再利用可能なものが必要な場合は、代わりに他の優れた提案されたソリューションのいずれかを使用してください。