2014-11-07 5 views
0

Я пытаюсь создать класс шаблона, который выполняет заданную пользователем N -ary функцию с аргументами типа C. Для этого мне нужно каким-то образом указать тип этой функции на основе параметров шаблона. Следующий код иллюстрирует мою проблему:Изменение параметра списка функции на основе параметра шаблона?

template <typename C, size_t N> 
class NaryDispatch { 

    typedef typename std::function<void(/* N parameters of type C& */)> NaryFn; 

    public: 
     NaryDispatch(NaryFn f) : m_function(std::forward<NaryFn>(f)) {} 

    private: 
     NaryFn m_function; 
}; 

Я не смог найти способ, чтобы построить тип станда :: функции с подписью соответствующей валентности. Я использую C++ 11 и Boost :: MPL, поэтому решения, связанные с ними, более чем приветствуются. Я пытался использовать SFINAE/параметр вывод шаблона на параметр конструктора следующим образом:

template < 
    class... Args, 
    typename std::enable_if<sizeof...(Args) == N, C>::type = 0 
> 
NaryDispatch(std::function<void(Args&...)> fn) : m_function(std::forward<???>(fn)) {} 

Как вы можете видеть, проблема здесь в том, что, поскольку я не смог определить тип функции будет взять данный шаблон параметры C и N, я не могу определить тип члена класса, в котором должна храниться функция.

Чтобы упростить мое намерение немного, для параметров шаблона C и N, конструктор класса должен принимать (и хранить в частном члена) в std::function, который возвращает void и принимает N параметров типа C&. Например, необходимо скомпилировать:

NaryDispatch<int, 3> disp([](int a, int b, int c) {}); 

Заранее благодарим за любые идеи, которые вы могли бы предложить.

ответ

4

Это не должно быть слишком сложно. Давайте начнем с верхнего уровня:

template <typename C, std::size_t N> 
struct NaryDispatch 
{ 
    // details, see below 

    using f_type = typename function_maker<C &, N>::type; 

    template <typename F> 
    NaryDispatch(F && f) : fn_(std::forward<F>(f)) {} 

    f_type fn_; 
}; 

Теперь мы просто должны реализовать черты function_maker:

template <typename T, std::size_t K, typename ...Args> 
struct function_maker 
{ 
    using type = typename function_maker<T, K - 1, T, Args...>::type; 
}; 

template <typename T, typename ...Args> 
struct function_maker<T, 0, Args...> 
{ 
    using type = std::function<void(Args...)>; 
}; 

Наконец, вы также можете предоставить какой-то стесненным вызова функции. Возможно, как это:

template <typename ...Args, 
      typename = typename std::enable_if<sizeof...(Args) == N>::type> 
void run(Args &&... args) 
{ 
    fn_(std::forward<Args>(args)...); 
} 
+0

Изменить 'арг ...' 'в Args и ...', так как он хочет ссылки. – 0x499602D2

+0

[Демо] (http://ideone.com/bqUyMd) –

+0

@ 0x499602D2: Выполнено. –

0

Ваша следующая проблема будет «Как передать N параметров к содержащемуся std::function?» Я думаю, что вы могли бы существенно упростить с помощью шаблона класса диспетчера, который работает с любым старым списком типов параметров:

template <typename...Args> 
class Dispatcher { 
    typedef typename std::function<void(Args...)> Fn; 

    public: 
     Dispatcher(Fn f) : m_function(std::move(f)) {} 

     void operator()(Args...args) { 
      m_function(std::forward<Args>(args)...); 
     } 

    private: 
     Fn m_function; 
}; 

вместе с небольшим количеством метапрограммирования для расчета правильной Dispatcher специализации для обработки N параметров типа C&:

template <typename C, size_t N, typename...Args> 
struct NaryDispatch_ { 
    using type = typename NaryDispatch_<C, N-1, Args..., C&>::type; 
}; 
template <typename C, typename...Args> 
struct NaryDispatch_<C, 0, Args...> { 
    using type = Dispatcher<Args...>; 
}; 

template <typename C, size_t N> 
using NaryDispatch = typename NaryDispatch_<C, N>::type; 

DEMO AT IDEONE

Смежные вопросы