我们可以使用可变参数模板函数来过滤特定类型的参数,然后将其余的函数传递给另一个函数吗?

时间:2016-04-20 14:33:36

标签: c++ templates c++11 variadic-templates

例如

// we have a variadic function
void print(...);    

// I need such a function to filter parameters of specific type
template<typename... Args>
void print_filter(const Args&... args)
{
    // filter non-integral type
    print(integral args);
}

// my goal, all non-integral type can be ignored:
print_filter(1.0, 2, "abc", 3) == print(2, 3)

我已经用尽了我的知识......你能帮忙吗?或者只是为了证明它是不可能的,这也是非常有帮助的。感谢

4 个答案:

答案 0 :(得分:3)

一个巧妙的技巧是将你想要的参数转换为1元转发元组,将你不想要的参数转换为空元组,tuple_cat结果,然后apply(C + +17)生成要调用的函数的元组:

template<typename... Args>
void print_filter(Args&&... args) {
    std::apply(
        [](auto&&... args) { return print(std::forward<decltype(args)>(args)...); },
        std::tuple_cat(
            std::get<std::is_integral<typename std::decay<Args>::type>::value ? 0 : 1>(
                std::make_tuple(
                    [](Args&& arg) { return std::tuple<Args&&>{std::forward<Args>(arg)}; },
                    [](Args&&) { return std::tuple<>{}; }))(
                std::forward<Args>(args))...));
}

请注意,这采用了另一种技巧,即使用get有条件地将两个函数之一应用于参数。

Example.

答案 1 :(得分:2)

#include <cstddef>
#include <type_traits>
#include <utility>
#include <tuple>

template <typename S, typename M, typename O = std::index_sequence<>>
struct filter : O {};

template <std::size_t I, std::size_t... Is, std::size_t... Js, std::size_t... Ks>
struct filter<std::index_sequence<I, Is...>, std::index_sequence<0, Js...>, std::index_sequence<Ks...>>
    : filter<std::index_sequence<Is...>, std::index_sequence<Js...>, std::index_sequence<Ks...>> {};

template <std::size_t I, std::size_t... Is, std::size_t... Js, std::size_t... Ks>
struct filter<std::index_sequence<I, Is...>, std::index_sequence<1, Js...>, std::index_sequence<Ks...>>
    : filter<std::index_sequence<Is...>, std::index_sequence<Js...>, std::index_sequence<Ks..., I>> {};

template <template <typename T> class F, typename... Args>
using Filter = filter<std::make_index_sequence<sizeof...(Args)>, std::index_sequence<F<Args>{}...>>;

template <typename... Args, std::size_t... Is>
void print_filter_impl(std::tuple<Args...>&& tuple, std::index_sequence<Is...>)
{
    print(std::get<Is>(std::move(tuple))...);
}

template <typename... Args>
void print_filter(Args&&... args)
{
    print_filter_impl(std::forward_as_tuple(std::forward<Args>(args)...), Filter<std::is_integral, std::decay_t<Args>...>{});
}

DEMO

答案 2 :(得分:0)

这是一种方法。首先创建一个虚拟分隔符类:

class SEP { };

然后,一个辅助函数通过将其他参数推送到参数列表的末尾来丢弃所有非整数参数:

template <class T, class... R>
void print_filter_(T x, R... a) {
  if (std::is_integral<T>::value) {
    print_filter_(a..., x);
  } else {
    print_filter_(a...);
  }
}

在完成所有初始参数之后,只剩下整数参数:

template <class... T>
void print_filter_(SEP, T... a) {
  print(a...);
}

最后,调用辅助函数:

template <class... T>
void print_filter(T... a) {
  print_filter_(a..., SEP());
}

答案 3 :(得分:0)

#include <iostream>
#include <type_traits>
#include <utility>
#include <tuple>

template <template <typename> class Predicate, std::size_t N, typename Output, typename... Args> struct find_indices_h;

template <template <typename> class Predicate, std::size_t N, std::size_t... Is, typename First, typename... Rest>
struct find_indices_h<Predicate, N, std::index_sequence<Is...>, First, Rest...> : std::conditional_t<
    Predicate<First>::value,
    find_indices_h<Predicate, N+1, std::index_sequence<Is..., N>, Rest...>,
    find_indices_h<Predicate, N+1, std::index_sequence<Is...>, Rest...>
> {};

template <template <typename> class Predicate, std::size_t N, typename Sequence>
struct find_indices_h<Predicate, N, Sequence> {
    using type = Sequence;
}; 

template <template <typename> class Predicate, typename... Args>
using find_indices = typename find_indices_h<Predicate, 0, std::index_sequence<>, Args...>::type;

template <typename... Args>
void print (Args&&... args) {
    const int a[] = {(std::cout << args << ' ', 0)...};
    static_cast<void>(a);
    std::cout << '\n';
}

template <typename F, typename Tuple, std::size_t... Is>
void partial_apply (F f, Tuple&& tuple, std::index_sequence<Is...>) {
    f(std::get<Is>(std::forward<Tuple>(tuple))...);
}

template<typename... Args>
void print_filter (const Args&... args) {
    const auto partial_print = [](auto&&... ps) { return print(std::forward<decltype(ps)>(ps)...); };
    partial_apply(partial_print, std::forward_as_tuple(args...), find_indices<std::is_integral, Args...>{});
}

int main() {
    std::cout << std::boolalpha;
    print_filter(1, "hello", 'a', true, 1.3, 1000);  // 1 a true 1000
}