Как получить указатель на любую перегрузку перегруженной функции, перегрузки которой неизвестны? - PullRequest
0 голосов
/ 01 июня 2018

У меня есть структура кода, где я беру указатель на перегруженную функцию, проверяю, какую перегрузку выполнить, static_cast Указатель на правильную перегрузку и запускает ее.

Проблема в том, что функция вызывающейотвечает за принятие указателя на любую перегрузку для этой функции, не может знать список существующих перегрузок.Таким образом, такой код:

auto ptr = &foobar;
invoke_correct_overload<decltype(ptr)>(ptr);

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

Context

У меня есть переменная номер std::variant, и необходимо передать его различным функциям в зависимости от значения, которое они содержат.Я нашел способ с массивом constexpr, чтобы найти, какую перегрузку выполнить, и пишу функцию, которая берет указатель на функцию, приводит все варианты в соответствие с индексом в массиве и выполняет его.

Текущая попытка

#define GENERAL_INTERFACE(SPE_FUNC, OPERANDS) do {\
        int valid_comb_index = evaluate_valid_types(valid_args_##SPE_FUNC, OPERANDS)); \
        constexpr [[maybe_unused]] auto foo = SPE_FUNC; \
        invoke_right_overload<valid_args_##SPE_FUNC.size(), \
                              valid_args_##SPE_FUNC[0].size() - 1, \                                   
                              valid_args_##SPE_FUNC, decltype(foo)> \                                                           
                              (valid_comb_index, OPERANDS,foo); \

template<std::size_t N, std::size_t P,
const std::array<std::array<int, 1>, N>& valid_args, typename T>
void invoke_right_overload(int valid_comb_index, 
std::vector<Operand> operands, T& funcptr) {
   if(valid_comb_index == P - 1) {
          auto to_invoke = static_cast<void(*)(decltype(std::get<valid_args[P][0]>(Operand())))>(funcptr);

          std::invoke(to_invoke, std::get<valid_args[P][0]>(operands[0]));
   }

   if constexpr (P - 1 == 0) return;

   invoke_right_overload<N, P - 1,  valid_args, T>(valid_comb_index, 
   operands, funcptr, apply_to);
   }

Проблема в функции, которую вызывает invoke_right_overload.Существует несколько «перегрузок» invoke_right_overload для 0, 1, 2 или 3 операндов, поэтому я не могу получить перегрузку, используя первую допустимую комбинацию, поскольку их может не быть.

Я знаю этовопрос не совсем правильно сформулирован, но не может найти какой-то конкретный момент, чтобы сделать его лучше.Я отредактирую вопрос так, как вам будет угодно для получения дополнительной информации.

Ответы [ 3 ]

0 голосов
/ 01 июня 2018

Используйте лямбду вместо необработанного указателя функции вместе с std::visit:

void foo(int) { std::cout << "int\n"; }
void foo(double) { std::cout << "double\n"; }

int main() {
    auto f = [](auto... params) { foo(params...); };

    std::variant<int, double> v = 42;
    std::visit(f, v); // will call foo(int)
    v = 3.14;
    std::visit(f, v); // will call foo(double)
}

Live Demo

0 голосов
/ 01 июня 2018

Удалить эту строку:

auto to_invoke = static_cast<void(*)(decltype(std::get<valid_args[P][0]>(Operand())))>(funcptr);

вам не нужен указатель на функцию.Вы хотите вызвать функцию для набора операндов, и для этого не требуется указатель на функцию.

Далее, вместо T& funcptr take T&& to_invoke.Это не указатель;указатель не представляет множественные перегрузки.

#define RETURNS(...) \
  noexcept(noexcept(__VA_ARGS__)) \
  ->decltype(__VA_ARGS__) \
  { return __VA_ARGS__; }

#define OVERLOADS_OF(...) \
  [](auto&&...args) \
  RETURNS(__VA_ARGS__( decltype(args)(args)... )

Теперь, если вы хотите отправить перегрузки функции foo, передайте OVERLOADS_OF(foo) как to_invoke.

0 голосов
/ 01 июня 2018

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

auto to_invoke = static_cast<
 void(*)(decltype(std::get<valid_args[P][0]>(Operand())))>(funcptr);

является попыткой изменить указатель функции foobar() с определенной сигнатурой на указатель функции сто же самое имя foobar(), но другая подпись ... просто не может работать: указатель на функцию - это указатель на функцию, и вы не можете просто привести его к указателю на другую функцию, надеющуюся перехватить функцию с помощьюто же имя, надеясь, что вызов может работать.

...