Либо что-то не так с моим пониманием C++, либо где-то скрытая опечатка... Я потратил часы на эти несколько LOC.
Сначала я определил метод start()
как таковой:
template <typename FunctionResult, typename ...FunctionArgs>
inline std::shared_ptr<StoppableThread> start(
std::function<FunctionResult(const bool&, FunctionArgs...)> function, FunctionArgs... args)
{ ... }
А также немного threadedSearch()
лямбда-функции:
std::function<void(const bool&,
const Source&, Population&,
const std::vector<Parameter>&,
const size_t&, const size_t&)> threadedSearch = ... ;
Но когда я пытаюсь это сделать:
Source source = { ... };
Population population = { ... };
const std::vector<Parameter> variationsParameters = { ... };
const size_t randomCandidatesCount = ..., lineageCount = ...;
auto searchThread = start(
threadedSearch,
source, population,
variationsParameters,
randomCandidatesCount, lineageCount);
Компилятор не согласен с последним вызовом starŧ()
и говорит мне:
# with g++
error: no matching function for call to
‘start(std::function<void(const bool&, const Source&, Population&, const std::vector<Parameter>&, const long unsigned int&, const long unsigned int&)>&,
Source&, Population&, const std::vector<Parameter>&, const size_t&, const size_t&)’
[...]
note: candidate: ‘template<class FunctionResult, class ... FunctionArgs> std::shared_ptr<StoppableThread>
start(std::function<FunctionResult(const bool&, FunctionArgs ...)>, FunctionArgs ...)
note: template argument deduction/substitution failed:
note: inconsistent parameter pack deduction with ‘const Source&’ and ‘Source’
# with clang++
error: no matching member function for call to 'start'
note: candidate template ignored: deduced conflicting types for parameter 'FunctionArgs'
(<const Source&, Population&, const std::vector<Parameter>&, const unsigned long&, const unsigned long&>
vs.
<Source, Population, std::vector<Parameter>, size_t, size_t>)
Мой вопрос: WTF?
И ещё: что я мог сделать? Явное указание параметров шаблона в вызове start<...>()
даже не сработало...
Я не знаю, как заставить компилятор понять, что он должен видеть как «настоящие» типы параметров...
Минимальный пример полного сбоя можно найти здесь: https://onlinegdb.com/FtBIGmkH-
Не этот ли?
Нет, мы не получим эту ошибку, если попытаемся скомпилировать ее.
О, ок, это интересно... Я посмотрю. Спасибо вам двоим за указание на это!
Где находится параметр const bool& в вашем вызове start?
@Issylin: start() не получает const bool& parameter
... только лямбда-функция принимает его (я знаю, это сбивает с толку)
Не этот ли? Скопируйте и вставьте этот код в файл foo.cpp. Скомпилируйте его. Он не может скомпилироваться. Грустная панда. Если мы «заполним пробелы» и если ошибка окажется в незаполненных полях, мы не сможем изобрести ошибку заново.
@Элджей: Готово. Извините, это заняло у меня некоторое время: onlinegdb.com/FtBIGmkH-
Ответ nm ниже является полным. В качестве быстрого решения я заставил ваш код работать, указав явные параметры шаблона auto searchThread = start<void, Source const&, Population&, std::vector<Parameter> const&, size_t const&, size_t const&>(/*...*/
.
Пожалуйста, не редактируйте решения в вопросе. Минимально воспроизводимый пример должен быть внутри вопроса и не полагаться на внешние ссылки.
whatever_t start(std::function<FunctionResult(const bool&, FunctionArgs...)> function,
FunctionArgs... args)
Здесь есть два случая FunctionArgs...
. Когда часть типа std::function
, контекст невыводим, и пакет будет взят из std::function
как есть. В другом случае контекст выводим, поэтому пакет будет выведен из фактического аргумента функции.
В обоих случаях обе упаковки должны быть абсолютно одинаковыми. Однако FunctionArgs... args
никогда не выведет ссылочный тип, и ваша функция принимает константные ссылки. Таким образом, один пакет будет полон константных ссылочных типов, а другой — нессылочных типов. Это неудачная замена.
Один из способов решить проблему — сделать невыводимым и другое вхождение.
whatever_t start(std::function<FunctionResult(const bool&, FunctionArgs...)> function,
std::type_identity_t<FunctionArgs>... args)
выполнит эту работу (требуется C++20, но в крайнем случае можно реализовать эквивалент std::type_identity_t
).
Другой способ — отделить тип функции от аргументов.
template<typename Func, typename ... Args>
whatever_t start(Func&& func, Args&& ... args)
(чтобы убедиться, что func
можно вызвать с помощью args
, вы можете использовать предложение requires
или старый добрый SFINAE — или просто вызвать его и обрабатывать менее полезные сообщения об ошибках, если вызов не может быть выполнен),
Покажите, пожалуйста, минимально воспроизводимый пример