2016-04-20 7 views
9

zum BeispielKönnen wir die variable Template-Funktion verwenden, um Parameter eines bestimmten Typs zu filtern und den Rest dann an eine andere Funktion zu übergeben?

// 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) 

Ich habe meine Kenntnisse aufgebraucht, das zu tun ... können Sie helfen? oder einfach um zu beweisen, dass es unmöglich ist, was auch sehr hilfreich ist. Danke

+0

Alle Antworten sind so genial, dass ich nicht, was man am besten entscheiden können, danke. –

Antwort

0

Hier ist eine Möglichkeit, es zu tun. Beginnen Sie mit einer Dummy-Separator-Klasse erstellen:

class SEP { }; 

Dann wird eine Hilfsfunktion, die alle nicht ganzzahligen Argumente verwirft durch die anderen Argumente an das Ende der Argumentliste drücken:

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...); 
    } 
} 

Nachdem man durch alle ursprünglichen Argumente ist es nur mit den integral denjenigen links:

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

Schließlich rufen sie die Hilfsfunktion:

template <class... T> 
void print_filter(T... a) { 
    print_filter_(a..., SEP()); 
} 
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

Kleine Änderungen in 'print_filter_impl', um Tupel weiterzuleiten: [Demo] (http://coliru.stacked-crooked.com/a/d58f1a1146a760a9) – Jarod42

+2

Eine weitere kleine Änderung am Filter - Alias, um das mitgelieferte Prädikat zu verwenden: [Demo] (http : //coliru.stacked-crooked.com/a/1622565e3ce690e4) – Andrew

3

Ein netter Trick ist es, die Argumente, die Sie in ein 1-Element Forwarding Tupel konvertieren möchten, die Argumente, die Sie nicht in ein leeres Tupel wollen, tuple_cat die Ergebnisse, dann apply (C++ 17) die resultierende Tupel auf die Funktion, die Sie aufrufen möchten:

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))...)); 
} 

Beachten Sie, dass dies ein weiterer Trick beschäftigt, die get zu verwenden ist bedingt eine von zwei functi anzuwenden ons zu einem Argument.

Example.

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 
}