Это похоже на ошибку компилятора; компилятор пытается вывести аргументы шаблона, когда все аргументы уже указаны явно и, следовательно, вычитание не требуется. Или, возможно, ошибка связана с подстановкой, которая должна завершиться успешно.
В соответствии со стандартом, можно явно указать аргументы variadi c pack. См. Пример в [temp.arg.explicit] / 5 :
template<class ... Args> void f2();
void g() {
f2<char, short, int, long>(); // OK
}
Когда все аргументы шаблона известны, предполагается, что компилятор просто создает экземпляр шаблон и покончим с этим; Разрешение перегрузки затем происходит в обычном режиме.
Чтобы обойти эту проблему, мы можем отключить вывод аргументов шаблона, введя не выводимый контекст. Например, вот так:
template<typename T> using no_deduce = typename std::common_type<T>::type;
template<typename A, typename B, typename ...Fs>
void func_tmpl1(no_deduce<std::function<A(Fs..., B)>> callable)
{
}
template<typename A, typename ...Fs>
void func_tmpl2(no_deduce<std::function<A(Fs...)>> callable)
{
}
(::type
здесь является зависимым типом и становится недетерминированным контекстом)
Теперь он прекрасно компилируется в g++
и clang++
, ссылка на coliru
Сказав это, обратите внимание, что std::function
в первую очередь предназначен для стирания типа и является дорогостоящей абстракцией поскольку он вызывает дополнительное косвенное обращение во время выполнения и является тяжелым объектом для передачи, поскольку он пытается сохранить копию любого возможного функтора, избегая при этом выделения кучи (что часто все еще происходит - тогда это большой пустой объект плюс выделение кучи).
Поскольку ваши функции уже являются шаблонами, вам действительно не нужно стирать тип; проще и эффективнее просто взять callable
в качестве аргумента шаблона.
template<typename Func>
void func_tmpl(Func callable) // that's all
{
}
Или, если вам нужно дифференцировать по callable
аргументам, можете использовать некоторые SFINAE:
#include <functional>
class Cls1{};
template<typename A, typename B, typename ...Fs, typename Func,
typename = std::enable_if_t<std::is_invocable_r_v<A, Func, Fs..., B> > >
void func_tmpl1(Func callable)
{
}
template<typename A, typename B, typename ...Fs, typename Func,
typename = std::enable_if_t<std::is_invocable_r_v<A, Func, B, Fs...> > >
void func_tmpl2(Func callable)
{
}
void func0(std::function<void(float, Cls1)> callable)
{
}
int main()
{
std::function<void(float, Cls1)> f1 = [](float a, Cls1 b){};
func0(f1); // func0 is not a template - so it requires type erasure
func0([](float a, Cls1 b){});
func_tmpl1<void, Cls1, float>(f1); // #1 OK
func_tmpl2<void, float, Cls1>(f1); // #2 OK
func_tmpl1<void, Cls1, float>([](float a, Cls1 b) {}); // #3 OK
func_tmpl2<void, float, Cls1>([](float a, Cls1 b) {}); // #4 OK
return 0;
}
ссылка на колиру