2014-11-15 3 views
1

Я пытался написать свою первую программу, используя вариативные шаблоны. В частности, аргументы упаковки для вызова функции с задержкой. Мое первоначальное предположение о вызове указателя функции, как показано ниже, не работает:Я хотел бы понять, что распаковка параметров в C++

template<typename... params> 
void TypeX<params...>::delayed_call() 
{ 
    auto xs = get_saved_args(); // returns tuple 
    (*func)(xs...); 
} 

После поисков я нашел этот ответ C++11: I can go from multiple args to tuple, but can I go from tuple to multiple args?

Ответ пользователем Kerrek SB работал, и выглядит лучше, чем другие альтернативы. К сожалению, я понимаю это лишь частично. Это его ответ:

// implementation details, users never invoke these directly 
namespace detail 
{ 
    template <typename F, typename Tuple, bool Done, int Total, int... N> 
    struct call_impl 
    { 
     static void call(F f, Tuple && t) 
     { 
      call_impl<F, Tuple, Total == 1 + sizeof...(N), Total, N..., sizeof...(N)>::call(f, std::forward<Tuple>(t)); 
     } 
    }; 

    template <typename F, typename Tuple, int Total, int... N> 
    struct call_impl<F, Tuple, true, Total, N...> 
    { 
     static void call(F f, Tuple && t) 
     { 
      f(std::get<N>(std::forward<Tuple>(t))...); 
     } 
    }; 
} 

// user invokes this 
template <typename F, typename Tuple> 
void call(F f, Tuple && t) 
{ 
    typedef typename std::decay<Tuple>::type ttype; 
    detail::call_impl<F, Tuple, 0 == std::tuple_size<ttype>::value, std::tuple_size<ttype>::value>::call(f, std::forward<Tuple>(t)); 
} 

Я понимаю, что это рекурсивное решение, которое заканчивается после того, как частично специализированная версия будет достигнута. Однако я не могу понять поток, и как именно f(std::get<N>(std::forward<Tuple>(t))...); превращается в распакованный вызов. В идеале я хотел бы увидеть подробное описание потока полностью от вызываемого пользователем вызова функции.

+2

Пропуски в 'F (станд :: получить (Std :: вперед (т)) ...);' это пакет расширения. Когда N является пакетом параметров, скажем, «0,1,2», тогда строка будет расширена компилятором до 'f (std :: get <0> (std: forward (t), std :: get <1> (std :: вперед (t), std :: get <2> (std: forward (t)); ' – jrok

ответ

1

Посмотрев на это какое-то время, я наконец-то пришел к чему-то логичному. В настоящее время я понимаю эту проблему с распаковкой. Я добавил комментарии в код для ясности.

template <typename F, typename Tuple, bool Done, int Total, int... N> 
struct call_impl 
{ 
    static void call(F f, Tuple && t) 
    { 
     call_impl<F, 
        Tuple, 
        Total == 1 + sizeof...(N), 
        Total, 
        // This is the tricky part: Initial N... is empty, so 
        // sizeof...(N) is going to be 0, which is fed to next 
        // call_impl. On subsequent invokation of "call" N will 
        // contain a single entry - '0'. All subsequent invokations 
        // will keep adding numbers to N until 
        // Total == 1 + sizeof...(N) 
        // evaluates to true. At that point template 
        // specialization below gets invoked and completes the 
        // recursive chain. 
        N..., 
        sizeof...(N)>::call(f, std::forward<Tuple>(t)); 
    }    
};     

template <typename F, typename Tuple, int Total, int... N> 
struct call_impl<F, Tuple, true, Total, N...> 
{ 
    static void call(F f, Tuple && t) 
    { 
     // This is the last call in the recusrive chain, so int... N is 
     // actually a tuple of numbers (unless the function being invoked takes 
     // no arguments) 
     // Ellipsis(...) causes the line below to be expanded to however many 
     // numbers the int... N contains: 
     // f(std::get<0>(std::forward<Tuple>(t)), 
     // std::get<1>(std::forward<Tuple>(t)), 
     // std::get<2>(std::forward<Tuple>(t)) 
     // ... 
     //); 
     f(std::get<N>(std::forward<Tuple>(t))...); 
    } 
};  

// user invokes this 
template <typename F, typename Tuple> 
void call(F f, Tuple && t) 
{ 
    // Strip all qualifiers from Tuple: constness, volatility, reference 
    // and return the typedef of underfyling Tuple type 
    typedef typename std::decay<Tuple>::type ttype; 

    // ttype should now be a plain tuple type, so tuple_size will return its 
    // size 
    // IMPORTANT: The int... N is not given below, which drives the recursive 
    // compilation 
    call_impl<F, 
       Tuple, 
       0 == std::tuple_size<ttype>::value, // for no argument functions this is 
       // always true, which doesn't trigger recursive call_impl, but 
       // immediately drops to partially specialized call_impl, which 
       // invokes the given function. 
       std::tuple_size<ttype>::value 
       /*int... N would go here, but nothing is supplied */ 
      >::call(f, std::forward<Tuple>(t)); 
} 
Смежные вопросы