Ошибка вывода/замены аргумента шаблона при вызове

Либо что-то не так с моим пониманием 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-

Покажите, пожалуйста, минимально воспроизводимый пример

Alan Birtles 04.05.2024 22:57

Не этот ли?

Mathieu Rodic 04.05.2024 22:59

Нет, мы не получим эту ошибку, если попытаемся скомпилировать ее.

Ted Lyngmo 04.05.2024 22:59

О, ок, это интересно... Я посмотрю. Спасибо вам двоим за указание на это!

Mathieu Rodic 04.05.2024 23:00

Где находится параметр const bool& в вашем вызове start?

Issylin 04.05.2024 23:01

@Issylin: start() не получает const bool& parameter... только лямбда-функция принимает его (я знаю, это сбивает с толку)

Mathieu Rodic 04.05.2024 23:04

Не этот ли? Скопируйте и вставьте этот код в файл foo.cpp. Скомпилируйте его. Он не может скомпилироваться. Грустная панда. Если мы «заполним пробелы» и если ошибка окажется в незаполненных полях, мы не сможем изобрести ошибку заново.

Eljay 04.05.2024 23:13

@Элджей: Готово. Извините, это заняло у меня некоторое время: onlinegdb.com/FtBIGmkH-

Mathieu Rodic 04.05.2024 23:27

Ответ nm ниже является полным. В качестве быстрого решения я заставил ваш код работать, указав явные параметры шаблона auto searchThread = start<void, Source const&, Population&, std::vector<Parameter> const&, size_t const&, size_t const&>(/*...*/.

Eljay 04.05.2024 23:52

Пожалуйста, не редактируйте решения в вопросе. Минимально воспроизводимый пример должен быть внутри вопроса и не полагаться на внешние ссылки.

Alan Birtles 05.05.2024 06:37
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
10
72
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
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 — или просто вызвать его и обрабатывать менее полезные сообщения об ошибках, если вызов не может быть выполнен),

Другие вопросы по теме