アップデート:
私は最終的に、短絡も使用する(したがって、比較を少なくする)より簡単な方法でこれを実現する方法を見つけました。
いくつかの機械が与えられた場合:
namespace detail
{
template<int I, int N, typename T, typename... Args>
struct find_index
{
static int call(std::tuple<Args...> const& t, T&& val)
{
return (std::get<I>(t) == val) ? I :
find_index<I + 1, N, T, Args...>::call(t, std::forward<T>(val));
}
};
template<int N, typename T, typename... Args>
struct find_index<N, N, T, Args...>
{
static int call(std::tuple<Args...> const& t, T&& val)
{
return (std::get<N>(t) == val) ? N : -1;
}
};
}
クライアントが最終的に呼び出す関数は、次の単純なトランポリンに要約されます。
template<typename T, typename... Args>
int find_index(std::tuple<Args...> const& t, T&& val)
{
return detail::find_index<sizeof...(Args), T, Args...>::
call(t, std::forward<T>(val));
}
最後に、プログラムでこれを使用する方法は次のとおりです。
#include <iostream>
int main()
{
std::tuple<int, int, int, int> a(2, 3, 1, 4);
std::cout << find_index(a, 1) << std::endl; // Prints 2
std::cout << find_index(a, 2) << std::endl; // Prints 0
std::cout << find_index(a, 5) << std::endl; // Prints -1 (not found)
}
そして、これがライブの例です。
編集:
後方検索を実行したい場合は、上記の機械とトランポリン機能を次のバージョンに置き換えることができます。
#include <tuple>
#include <algorithm>
namespace detail
{
template<int I, typename T, typename... Args>
struct find_index
{
static int call(std::tuple<Args...> const& t, T&& val)
{
return (std::get<I - 1>(t) == val) ? I - 1 :
find_index<I - 1, T, Args...>::call(t, std::forward<T>(val));
}
};
template<typename T, typename... Args>
struct find_index<0, T, Args...>
{
static int call(std::tuple<Args...> const& t, T&& val)
{
return (std::get<0>(t) == val) ? 0 : -1;
}
};
}
template<typename T, typename... Args>
int find_index(std::tuple<Args...> const& t, T&& val)
{
return detail::find_index<0, sizeof...(Args) - 1, T, Args...>::
call(t, std::forward<T>(val));
}
これが実際の例です。
元の答え:
これは、タプルを使用する典型的な方法のようには聞こえませんが、本当にこれを行いたい場合は、次の方法があります (任意のサイズのタプルで動作します)。
まず、いくつかの機械 (よく知られたインデックスのトリック):
template <int... Is>
struct index_list { };
namespace detail
{
template <int MIN, int N, int... Is>
struct range_builder;
template <int MIN, int... Is>
struct range_builder<MIN, MIN, Is...>
{
typedef index_list<Is...> type;
};
template <int MIN, int N, int... Is>
struct range_builder : public range_builder<MIN, N - 1, N - 1, Is...>
{ };
}
template<int MIN, int MAX>
using index_range = typename detail::range_builder<MIN, MAX>::type;
次に、いくつかのオーバーロードされた関数テンプレート:
#include <tuple>
#include <algorithm>
template<typename T, typename... Args, int... Is>
int find_index(std::tuple<Args...> const& t, T&& val, index_list<Is...>)
{
auto l = {(std::get<Is>(t) == val)...};
auto i = std::find(begin(l), end(l), true);
if (i == end(l)) { return -1; }
else { return i - begin(l); }
}
template<typename T, typename... Args>
int find_index(std::tuple<Args...> const& t, T&& val)
{
return find_index(t, std::forward<T>(val),
index_range<0, sizeof...(Args)>());
}
使用方法は次のとおりです。
#include <iostream>
int main()
{
std::tuple<int, int, int, int> a(2, 3, 1, 4);
std::cout << find_index(a, 1) << std::endl; // Prints 2
std::cout << find_index(a, 2) << std::endl; // Prints 0
std::cout << find_index(a, 5) << std::endl; // Prints -1 (not found)
}
そして、これがライブの例です。