0

I have a code structure where I grab an overloaded function pointer, check which overload to execute, static_castthe pointer to its correct overload and runs it.

The problem is, the caller function, which is responsible for taking a pointer to any overload to this function, can't know the list of existing overloads. That being, code such as this :

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

Cannot work, because the first line is ambiguous. Is there a way to specify that the overload doesn't matter in the first line, or that it should be the first overload the compiler finds ?

Context

I have a variable number of std::variant, and need to feed it to different functions depending on the value they hold. I have figured out a way with a constexpr array to find which overload to execute, and am writing a function that takes a pointer to a function, casts all the variants according to an index in the array, and executing it.

Current attempt

#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);
   }

The problem is with the function that calls invoke_right_overload. There are multiple "overloads" of invoke_right_overload for 0, 1, 2 or 3 operands, so I can't get the overload using the first valid combination, for there may be none.

I know this question isn't really well-formed, but cannot find any specific point to make better. I will edit the question as much as you like for more information.

Community
  • 1
  • 1

3 Answers3

2

Use a lambda instead of a raw function pointer along with 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

Miles Budnek
  • 28,216
  • 2
  • 35
  • 52
0

Not sure that this is the point of your problem but if this instruction

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

is the attempt to change the pointer of a foobar() function with a specific signature to a pointer of a function with the same foobar() name but a different signature... simply can't work: a pointer to a function is a pointer to a function and you can't simply cast it to a pointer to another function hoping to intercept a function with the same name hoping that the call can work.

max66
  • 65,235
  • 10
  • 71
  • 111
  • Doesn't your answer go in contradiction with https://stackoverflow.com/a/2942442/7588952 ? – Sachiko.Shinozaki Jun 01 '18 at 18:46
  • @Sachiko.Shinozaki - no... I don't think so; with `void (*fpc)(char) = &f;` your saying the compiler: "select the pointer to the specific `f()` function that receive a `char` and return `void`", so the compiler know the right `f()` to choose; the same (If I'm not wrong) with `static_cast(&f)`; but in your case you have selected **before** a specific `f()` pointer and you can't convert to another `f()`. – max66 Jun 01 '18 at 18:51
0

Remove this line:

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

you don't want a pointer to a function. You want to invoke a function on a set of operands, and that doesn't require a pointer to a function.

Next, instead of T& funcptr take T&& to_invoke. It isn't a pointer; a pointer does not represent multiple overloads.

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

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

Now if you want to dispatch to overloads of a function foo pass OVERLOADS_OF(foo) as to_invoke.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524