2016-07-31 14 views
5

że ma następujący fragment kodu gdzie określenia struct quick z matrycy static metodą random z pewnych kierunków (. I. Używane function_traits od drugiej tak odpowiedzi mocowana do spodzie odniesienie)Jak uzyskać wszystkie typy parametrów z pakietu parametrów?

struct quick 
{ 
    template <typename T> 
    static T random(); 

    template <typename F> 
    static void check(F f) 
    { 

    constexpr auto arity = function_traits<F>::arity; // easy :) 
    std::cout << arity << std::endl; 
    typedef typename function_traits<F>::template arg<0>::type type0; // easy:) 
    // how to get all types of all F's parameters? 
    } 
}; 

template <> 
std::string quick::random<std::string>() 
{ 
    return std::string("test"); 
} 

template <> 
int quick::random<int>() 
{ 
    return 1; 
} 

Chciałbym uzyskać wszystkie typy parametrów F wewnątrz check, dzięki czemu mogę generować tuple z losowymi wpisami (na podstawie moich specjalizacji metody random).

tak:

auto t0 = std::make_tuple(quick::random<AllTypes>()...); //pseudo code 
auto t = 
    std::make_tuple(quick::random < 
            function_traits<F>::template arg<std::make_index_sequence<arity>>::type... 
            > 
           ()... 
        ); 

Próbowałem coś podobnego:

template<typename F, typename ...TIdxs> 
using ArgTypes = typename function_traits<F>::template arg<TIdxs>::type...; 

// ... 
// inside check 

typedef ArgTypes<F, std::make_index_sequence<arity>> types; 

ale nie zdało egzaminu:

main.cpp:80:72: error: expected ‘;’ before ‘...’ token 
using ArgTypes = typename function_traits<F>::template arg<TIdxs>::type...; 
                     ^
main.cpp: In static member function ‘static void quick::check(F, D)’: 
main.cpp:98:15: error: ‘ArgTypes’ does not name a type 
     typedef ArgTypes<F, std::make_index_sequence<arity>> types; 

Użyłem function traits narzędziowe z this Odpowiedź SO.

template <typename T> 
struct function_traits : function_traits<decltype(&T::operator())> 
{}; 
// For generic types, directly use the result of the signature of its 'operator()' 

template <typename ClassType, typename ReturnType, typename... Args> 
struct function_traits<ReturnType(ClassType::*)(Args...) const> 
// we specialize for pointers to member function 
{ 
    enum { arity = sizeof...(Args) }; 
    // arity is the number of arguments. 

    typedef ReturnType result_type; 

    template <size_t i> 
    struct arg 
    { 
     typedef typename std::tuple_element<i, std::tuple<Args...>>::type type; 
     // the i-th argument is equivalent to the i-th tuple element of a tuple 
     // composed of those arguments. 
    }; 
}; 
+0

jak zwykle cech funkcjonalnych onky działa czasami. 'auto f = [] (auto && x) {return 2 * x;}'. – Yakk

Odpowiedz

-1

Nie wiesz, że to, co chcesz, ale ... co o modyfikowania quick w następujący sposób?

struct quick 
{ 
    template <typename T> 
    static T random(); 

    template<typename F, std::size_t I> 
    using ArgTypes = typename function_traits<F>::template arg<I>::type; 

    template<typename F, std::size_t ... Is> 
    using ArgTuple = std::tuple< ArgTypes<F, Is>... >; 

    template <typename F, std::size_t ... Is> 
    static ArgTuple<F, Is...> makeArgTuple() 
    { return make_tuple(quick::random<Is>()...); } 

    template <typename F> 
    static void check(F f) 
    { 

    constexpr auto arity = function_traits<F>::arity; // easy :) 
    std::cout << arity << std::endl; 

    typedef typename function_traits<F>::template arg<0>::type type0; // easy:) 

    auto t = ArgTuple<F, std::make_index_sequence<arity>::type>(); 

    auto t2 = makeArgTuple<F, std::make_index_sequence<arity>::type>(); 
    } 

}; 

Myliłeś przechodząc typename s TIdxs do arg; arg potrzebuje std::size_t.

Weź pod uwagę, że std::make_index_sequence jest to funkcja C++ 14 (ale można ją łatwo utworzyć również w C++ 11).

p.s .: przepraszam za mój zły angielski.

+0

dotyczące 'TIdxs': chciałem go rozwinąć, aby uzyskać wyniki:' arg <0>, arg <1>, arg <2> ... ' – Patryk

+0

@Patryk - na pewno; ale jako 'std :: size_t', a nie jako' typename'; Mam na myśli: nie jest źle 'szablon '; powinien być 'szablon ' – max66

+0

Ahh tak. Masz rację. Ale nadal nie mogę uzyskać wyniku końcowego 'auto t = std :: make_tuple (quick :: random <... what_here ...>());' – Patryk

2
template<class=void,std::size_t...Is> 
auto tupler(std::index_sequence<Is...>){ 
    return [](auto&&f){ 
    return std::make_tuple(
     f(std::integral_constant<std::size_t,Is>{})... 
    ); 
    } 
} 
template<std::size_t N> 
auto tupler(){ 
    return tupler(std::make_index_sequence<N>{}); 
} 

Umożliwia to rozwijanie pakietów parametrów i tworzenie krotek.

Wystarczy

auto t = tupler<ArgCount>()([&](auto i){ 
    return random<typename func_trait::arg<i>::type>(); 
}); 

Gdzie func_trait jest aliasem do rzeczy powyżej.

Na marginesie zamień struct arg na alias using. Odkurzacz.

3

Zauważ, że w function_traits, masz już , masz wszystkie typy argumentów. Wszystko co musisz zrobić, to narazić je:

template <typename ClassType, typename ReturnType, typename... Args> 
struct function_traits<ReturnType(ClassType::*)(Args...) const> 
// we specialize for pointers to member function 
{ 
    enum { arity = sizeof...(Args) }; 

    using result_type = ReturnType; 

    using all_args = std::tuple<Args...>; // <-- add this 

    template <size_t i> // <-- consider making this an alias template 
    using arg = std::tuple_element_t<i, all_args>; 
}; 

a teraz coraz wszystkie argumenty funkcji jest po prostu function_traits<F>::all_args.


Jeśli nie chcesz zmieniać function_traits, musimy tylko dodać zewnętrznego metafunkcji:

template <class F, class = std::make_index_sequence<function_traits<F>::arity>> 
struct all_args; 

template <class F, size_t... Is> 
struct all_args<F, std::index_sequence<Is...>> { 
    using type = std::tuple<typename function_traits<F>::template arg<Is>::type...>; 
}; 

template <class F> 
using all_args_t = typename all_args<F>::type; 
Powiązane problemy