最近做cinatra遇到這樣的需求,根據一個type來獲取對應的第一個元素,需要注意的一個問題是,如果沒有這個類型的時候,通過編譯期斷言提醒使用者,實現代碼如下:
1.C++14實現
template <class T, std::size_t N, class... Args> struct indexOf; template <class T, std::size_t N, class... Args> struct indexOf<T, N, T, Args...> { static constexpr auto value = N; }; template <class T, std::size_t N, class U, class... Args> struct indexOf<T, N, U, Args...> { static constexpr auto value = indexOf<T, N + 1, Args...>::value; }; template <class T, std::size_t N> struct indexOf<T, N> { static constexpr auto value = -1; static_assert(value!=-1, "the type is not exist"); }; template <class T, class... Args> T get_element_by_type(const std::tuple<Args...>& t) { return std::get<indexOf<T, 0, Args...>::value>(t); }
2.C++11的實現方法
template <class T, std::size_t N, class... Args> struct indexOf; template <class T, std::size_t N, class... Args> struct indexOf<T, N, T, Args...> { enum { value = N }; }; template <class T, std::size_t N, class U, class... Args> struct indexOf<T, N, U, Args...> { enum { value = indexOf<T, N + 1, Args...>::value}; }; template <class T, std::size_t N> struct indexOf<T, N> { enum { value = -1 }; static_assert(value!=-1, "the type is not exist"); };
把enum換成const int也沒問題,如果完全用C++11的方式去做那就用std::integral_constant吧,代碼如下:
template <class T, std::size_t N, class... Args> struct indexOf; template <class T, std::size_t N, class... Args> struct indexOf<T, N, T, Args...> : std::integral_constant<int, N> { }; template <class T, std::size_t N, class U, class... Args> struct indexOf<T, N, U, Args...> : std::integral_constant<int, indexOf<T, N + 1, Args...>::value> { }; template <class T, std::size_t N> struct indexOf<T, N> : std::integral_constant < int, -1 > { }; template <class T, class... Args> T get_element_by_type(const std::tuple<Args...>& t) { return std::get<indexOf<T, 0, Args...>::value>(t); }
注意,integral_constant方式,加斷言不起作用,不過會返回一個無效的-1,在外層也會出現斷言提示,問題不大。
測試代碼:
std::tuple<int, double, char, short> tp = std::make_tuple(1, 2.3, 2, 1); //auto r = get_element_by_type<string>(tp); //編譯期斷言錯誤 auto r = get_element_by_type<double>(tp); //返回2.3