2015-08-31 9 views
1

У меня есть метод следующей подписи:автоматического преобразования от повышающего :: bind_t увеличить :: Функция

template<typename T> 
void 
register_msg_action(const pmt::pmt_t& name, 
     boost::function<T(pmt::pmt_t)> converter, 
     boost::function<void(T)> action) 

(pmt_t полный тип, прежде чем спросить)

, а также перегрузки которые принимают T converter(pmt::pmt_t) и void converter(T) (т.е. исходные функции C/C++), а также все перестановки выше boost::function<> и аргументы функции стиля C. Это оставляет меня с 4 разными способами.

Я хотел бы избежать увеличения количества методов. Тем не менее, наиболее распространенным, что я буду делать это вызов что-то вроде

register_msg_action(pmt::mp("key"), 
    pmt::to_long, /* "raw" function long(pmt_t) */ 
    boost::bind(&my_class::void_method_of_long, this, _1) /* CAVEAT */ 
); 

Мой подход был, что /* CAVEAT */ аргумент неявно конвертируются в boost::function<void(T)>, но тем не менее, это не кажется, случай (г ++ 5.1. 1):

error: no matching function for call to ‘register_msg_action(pmt::pmt_t, boost::function<long int(boost::intrusive_ptr<pmt::pmt_base>)>&, boost::_bi::bind_t<void, void (*)(long int), boost::_bi::list1<boost::arg<1> > >)’ 
    register_msg_action(pmt::mp("hi"), long_function, boost::bind(&my_class::void_method_of_long, this ,_1)); 

... все остальные кандидаты (boost :: function, boost :: function); (Т (pmt_t), повышение :: функции); (T (pmt_t), недействительным (T)) ...

test.cc:56:1: note: candidate: template<class T> void register_msg_action(const pmt_t&, T (*)(pmt::pmt_t), boost::function<void(T)>) 
register_msg_action(const pmt::pmt_t& name, 
^ 
test.cc:56:1: note: template argument deduction/substitution failed: 
test.cc:80:76: note: ‘boost::_bi::bind_t<void, void (*)(long int), boost::_bi::list1<boost::arg<1> > >’ is not derived from ‘boost::function<void(T)>’ 
    register_msg_action(pmt::mp("key"), pmt::to_long, boost::bind(&my_class::void_method_of_long, this, _1)); 

Теперь, делая

boost::function<void(long)> action (boost::bind(&my_class::void_method_of_long, this, _1)); 
register_msg_action(pmt::mp("key"), pmt::to_long, action); 

работает прекрасно. Поскольку есть даже конструктор, который принимает boost::_bi::bind_t в boost::function, интересно, что я должен сделать, чтобы сделать эту работу, без

  • реализовав boost::function
  • опираясь на C++ 11 или более поздней версии (не может сделать , поддержка устаревших версий компилятор)
  • использование boost:phoenix для функционального программирования (попробовала бы это, но версия наддува мы должны поддерживать не все имеют phoenix еще.

Я боюсь добавить тип третьего аргумента в качестве дополнительного имени шаблона шаблона, потому что это нарушит безопасность типа списка параметров, которая необходима для гарантии работы action(converter(pmt::pmt_t)), и, честно говоря, я бы скорее рассмотрел больше кода, чем изучил пользовательский templated g ++ errors позже.

ответ

3

Проблема возникает, когда T появляется в подписи register_msg_action в сообщениях шаблона из boost::function. Тогда, если вы не вызываете его с фактическим объектом boost::function, его невозможно вывести. Он должен работать, если указать аргумент шаблона явно:

register_msg_action<long>(pmt::mp("key"), 
    pmt::to_long, /* "raw" function long(pmt_t) */ 
    boost::bind(&my_class::void_method_of_long, this, _1) 
); 

Если вы хотите сохранить возможность выведения T при использовании по меньшей мере, один обычная-аргумента функции, у вас есть возможность явно указать T, не выводимы в boost::function использования:

template <class T> 
struct NonDeduced 
{ 
    typedef T type; 
}; 

// T has to be specified explicitly at call site 
template<typename T> 
void 
register_msg_action(const pmt::pmt_t& name, 
     boost::function<typename NonDeduced<T>::type (pmt::pmt_t)> converter, 
     boost::function<void(typename NonDeduced<T>::type)> action) 

// T deducible from converter 
template<typename T> 
void 
register_msg_action(const pmt::pmt_t& name, 
     T converter(pmt::pmt_t), 
     boost::function<void(typename NonDeduced<T>::type)> action) 

// T deducible from action 
template<typename T> 
void 
register_msg_action(const pmt::pmt_t& name, 
     boost::function<typename NonDeduced<T>::type (pmt::pmt_t)> converter, 
     void action(T)) 

// T deducible from both, must match 
template<typename T> 
void 
register_msg_action(const pmt::pmt_t& name, 
     T converter(pmt::pmt_t), 
     void action(T)) 

[Live example]

+0

Это делает, на самом деле! Я переработаю свой синтаксис, чтобы сделать эту функцию, а не дополнительную нагрузку на пользователя. –

+0

Кстати, заставляя моего пользователя указывать аргумент шаблона, мой номер метода уменьшился бы до 1, что, я думаю, является улучшением. Я думаю, что лучше заставить пользователя делать что-то явно, чем предлагать ему возможность сделать что-то, что может заставить даже кого-то, у кого есть опыт повышения, потратить минуты, чтобы понять, о чем компилятор жалуется. –