You could use SFINAE with some std::tuple
functionality help (c++11 capable code):
#include <type_traits>
#include <tuple>
#include <iostream>
template <typename ...Us>
typename std::enable_if<!std::is_same<typename std::tuple_element<sizeof...(Us) - 1, std::tuple<Us...>>::type, int>::value>::type foo(Us...) {
std::cout << "A\n";
}
template <typename ...Us>
typename std::enable_if<std::is_same<typename std::tuple_element<sizeof...(Us) - 1, std::tuple<Us...>>::type, int>::value>::type foo(Us...) {
std::cout << "B\n";
}
int main(){
foo(1,2,3);
}
Output:
B
If you want it to test if some other parameter from pack is of a given type just change std::tuple_element
first parameter to desired index value.
[live demo]
If you wish to also utilize other parameters form parameter pack e.g. by recursive call, then your in bigger trouble... c++11 does not come with the functionality of creating index pack. You either need to implement that functionality yourself
#include <tuple>
#include <utility>
#include <iostream>
#include <initializer_list>
template <class T, T... Vs>
struct integer_sequence { };
template <class T, class, class, class = integer_sequence<T>, class = integer_sequence<T, 0>, class = void>
struct make_integer_sequence_impl;
template <class T, T ICV1, T... Res, T... Pow>
struct make_integer_sequence_impl<T, std::integral_constant<T, ICV1>, std::integral_constant<T, 0>, integer_sequence<T, Res...>, integer_sequence<T, Pow...>, typename std::enable_if<(ICV1 > 0)>::type>: make_integer_sequence_impl<T, std::integral_constant<T, ICV1/2>, std::integral_constant<T, ICV1%2>, integer_sequence<T, Res...>, integer_sequence<T, Pow..., (Pow + sizeof...(Pow))...>> { };
template <class T, T ICV1, T... Res, T... Pow>
struct make_integer_sequence_impl<T, std::integral_constant<T, ICV1>, std::integral_constant<T, 1>, integer_sequence<T, Res...>, integer_sequence<T, Pow...>, void>: make_integer_sequence_impl<T, std::integral_constant<T, ICV1/2>, std::integral_constant<T, ICV1%2>, integer_sequence<T, Pow..., (Res + sizeof...(Pow))...>, integer_sequence<T, Pow..., (Pow + sizeof...(Pow))...>> { };
template <class T, class Res, class Pow>
struct make_integer_sequence_impl<T, std::integral_constant<T, 0>, std::integral_constant<T, 0>, Res, Pow, void> {
using type = Res;
};
template <class T, T V>
using make_integer_sequence = typename make_integer_sequence_impl<T, std::integral_constant<T, V/2>, std::integral_constant<T, V%2>>::type;
template <size_t V>
using make_index_sequence = make_integer_sequence<size_t, V>;
template <size_t... V>
using index_sequence = integer_sequence<size_t, V...>;
void foo() { }
template <typename ...Us>
void foo(Us... us);
template <typename ...Us, std::size_t... Is>
typename std::enable_if<!std::is_same<typename std::tuple_element<sizeof...(Us) - 1, std::tuple<Us...>>::type, int>::value>::type foo_impl(index_sequence<Is...>, Us... us) {
std::cout << std::get<sizeof...(Us) - 1>(std::forward_as_tuple(us...)) << "A\n";
foo(std::get<Is>(std::forward_as_tuple(us...))...);
}
template <typename ...Us, std::size_t... Is>
typename std::enable_if<std::is_same<typename std::tuple_element<sizeof...(Us) - 1, std::tuple<Us...>>::type, int>::value>::type foo_impl(index_sequence<Is...>, Us... us) {
std::cout << std::get<sizeof...(Us) - 1>(std::forward_as_tuple(us...)) << "B\n";
foo(std::get<Is>(std::forward_as_tuple(us...))...);
}
template <typename ...Us>
void foo(Us... us) {
foo_impl(make_index_sequence<sizeof...(Us) - 1>{}, std::forward<Us>(us)...);
}
int main(){
foo(1,2,3);
}
[live demo]
or reconsider parameters access pattern:
#include <iostream>
void foo() { }
template <typename Other, typename ...Us>
void foo(Other first, Us... rest) {
foo(rest...);
std::cout << first << "A\n";
}
template <typename ...Us>
void foo(int first, Us... rest) {
foo(rest...);
std::cout << first << "B\n";
}
int main(){
foo(1,2,3);
}
[live demo]