2016-04-20 14 views
9

per esempioPossiamo usare la funzione modello variadic per filtrare i parametri di tipo specifico, quindi passare il resto a un'altra funzione?

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

ho usato la mia conoscenza per farlo ... potete aiutarmi? o solo per dimostrare che è impossibile, che è anche molto utile. Grazie

+0

Tutte le risposte sono così ingegnoso che non riesco a decidere quale è il migliore, grazie. –

risposta

0

Ecco un modo per farlo. Inizia creando una classe separatore dummy:

class SEP { }; 

Poi, una funzione di supporto che elimina tutti gli argomenti non interi spingendo gli altri argomenti al fine dell'elenco di argomenti:

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

Dopo aver attraversato tutti gli argomenti iniziali, si è lasciato con solo quelli integrali:

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

Infine, chiamare la funzione di supporto:

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

Modifiche minime in 'print_filter_impl' per inoltrare la tupla: [Demo] (http://coliru.stacked-crooked.com/a/d58f1a1146a760a9) – Jarod42

+2

Un'altra modifica minore dell'alias al filtro per utilizzare il predicato fornito: [Demo] (http : //coliru.stacked-crooked.com/a/1622565e3ce690e4) – Andrew

3

Un trucco è quello di convertire gli argomenti che si desidera in un 1-elemento di inoltro tuple, gli argomenti che non si desidera in una tupla vuota, tuple_cat i risultati, allora apply (C++ 17) la tupla risultante alla funzione che si desidera richiamare:

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

si noti che questo impiega un altro trucco, che è quello di utilizzare get per applicare condizionale uno dei due functi a un argomento.

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 
}