Проблема в том, что если в шаблоне один из его параметров функции не является ссылочным типом до начала вывода, этот параметр никогда не будет выводиться в ссылочный тип. Таким образом, при вычете с левой стороны, T
дает int
, но при вычете с правой стороны, T
дает int&
. Это ошибка, и компилятор жалуется.
Лучше всего сделать параметр функции того же типа, что и тип параметра указателя функции:
template<typename T> struct identity { typedef T type; };
template<typename T>
void f(typename identity<T>::type t, void (*func)(T)) {}
Используя identity<T>::type
, вы отключаете вычет на левой стороне. Как только T
был определен с правой стороны, T
устанавливается на левую сторону и выдает окончательный тип параметра.
Один парень предложил использовать правую сторону в качестве параметра шаблона - это хорошо, поскольку он может затем принимать объекты функций с перегруженной operator()
. Но тогда вы сталкиваетесь с проблемой необходимости знать, хочет ли он ссылки или нет. Чтобы решить эту проблему, boost
имеет reference_wrapper
(кстати, boost
также имеет шаблон identity
выше).
template<typename T, typename F>
void f(T t, F func) {}
Теперь, если вы хотите передать ссылку, а не копию, вы можете сделать это следующим образом
int i;
f(boost::ref(i), some_function);
ref
возвращает объект reference_wrapper, который неявно преобразуется в T&
. Поэтому, если вы вызываете func(t)
, t
автоматически преобразуется в целевую ссылку. Если вы не хотите передавать ссылку, просто передайте i
напрямую.