Ошибка вывода аргумента шаблона из-за непоследовательности - PullRequest
2 голосов
/ 13 июня 2019

Рассмотрим следующее (которое не компилируется , но мы исправим это в ближайшее время):

void foo(const int *n) { }

template <typename ...Args>
void bar(void (*func)(Args...), Args... args) { func(args...); }

int main(int argc, char *argv[])
{
    int n = 42;
    bar(foo, &n);
}

Функция шаблона bar() принимает указатель функции для вызова и пакет параметров для передачи ей. gcc 7.4.0 диагностирует следующую ошибку:

test.cpp:6:6: note:   template argument deduction/substitution failed:
test.cpp:11:16: note:   inconsistent parameter pack deduction with ‘const int*’ and ‘int*’

Очевидно, что правила удержания типа недостаточно ослаблены, чтобы можно было вывести const T* при соблюдении const T* и T*. Хорошо. Это достаточно легко исправить с помощью приведения :

bar(foo, static_cast<const int *>(&n));

Но это безобразно. C ++ 17 имеет std::as_const(), что делает его немного менее уродливым (&std::as_const(n)), но в моем текущем проекте я ограничен C ++ 14, sadface.

Q : Есть ли способ перегруппировать этот код так, чтобы вывод типа выполнялся успешно без явного указания параметров шаблона для bar() и без приведения для разрешения неоднозначной константности? Разрешается нестандартное мышление, если я могу передать указатель на функцию и ее аргументы в шаблонную функцию!

1 Ответ

5 голосов
/ 13 июня 2019

Вы можете отделить вычет для указателя функции и параметров:

void foo(const int *n) {}

template <typename... FArgs, typename... Args>
void bar(void (*func)(FArgs...), Args&&... args) {
    func(std::forward<Args>(args)...);
}

int main(int argc, char *argv[]) {
    int n = 42;
    bar(foo, &n);
}

Но в этот момент мне интересно, почему указатель функции должен быть разложен. Почему бы не принять вызов?

void foo(const int *n) {}

template <typename F, typename... Args>
void bar(F func, Args&&... args) {
    func(std::forward<Args>(args)...);
}

int main(int argc, char *argv[]) {
    int n = 42;
    bar(foo, static_cast<const int *>(&n));
    bar([](int const*){}, &n);
}

Также помните, что C ++ 17 предлагает std::invoke:

std::invoke(foo, &n);
...