У меня есть шаблонная функция, которая должна принимать указатель на функцию и аргументы, а затем вызывать указатель на функцию с заданными аргументами (назовем ее Invoke
).Однако, когда я вызываю функцию шаблона с перегруженной функцией в качестве аргумента, вывод шаблона завершается неудачей.
Я использовал enable_if, чтобы была допустима только одна перегрузка, но это не помогло.
#include <string>
#include <type_traits>
void foo(int, int){}
void foo(std::string, std::string) {}
template <bool Val1, bool Val2, bool ...Rest>
struct And
{
enum {value = And<Val1 && Val2, Rest...>::value};
};
template <bool Val1, bool Val2>
struct And<Val1, Val2>
{
enum {value = Val1 && Val2};
};
template <typename ...Params, typename ...Args, typename = typename std::enable_if<
And<std::is_convertible<Args, Params>::value...>::value
>::type>
void Invoke(void (*fn)(Params...), Args ...args){}
int main() {
Invoke(&foo, "a", "b");
return 0;
}
Попробуйте ideone .
Компилятор жалуется на mismatched argument pack lengths while expanding ‘std::is_convertible<Args, Params>::value’
, когда присутствуют обе перегрузки.Когда я закомментирую перегрузку int
, программа прекрасно компилируется, а когда я закомментирую перегрузку std::string
, дедукция завершается неудачно, как и должно быть, поскольку const char[]
неявно не преобразуется в int
.
Стандарт (раздел 17.8.2.1.6.2 стандарта C ++ 17) гласит следующее:
Если аргумент является набором перегрузки (не содержащим шаблонов функций), вычет пробного аргумента равенпопытался использовать каждого из членов набора.Если вывод выполняется успешно только для одного из членов набора перегрузки, этот элемент используется в качестве значения аргумента для вывода.Если вывод выполняется успешно для более чем одного члена набора перегрузки, параметр обрабатывается как недедуцированный контекст.
Поэтому я ожидаю, что компилятор попытается перегрузить int
, где вывод будетпотерпеть поражение.Когда он пытается перегрузить std::string
, вычет будет успешным.
Поскольку вычет будет успешным только для одного из членов набора перегрузки, я ожидаю, что тогда он будет действовать так, как если бы перегрузка int
не произошла.не существует, и компиляция будет успешной, как это происходит, когда другая перегрузка закомментирована, но это не удается.
Где я ошибаюсь?
Ссылки на стандарт будут приветствоваться.