如何获取指向过载函数的任何重载的指针,其重载未知?

时间:2018-06-01 18:16:14

标签: c++ templates g++ c++17

我有一个代码结构,我在其中获取一个重载的函数指针,检查要执行的重载,static_cast指向其正确重载的指针并运行它。

问题是,调用者函数负责获取指向任何重载此函数的指针,但无法知道现有重载的列表。那就是这样的代码:

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

无法正常工作,因为第一行含糊不清。有没有办法指定重载在第一行中无关紧要,或者它应该是编译器找到的第一个重载?

上下文

我的变量号为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的功能。对于0,1,2或3个操作数,invoke_right_overload有多个“重载”,因此我无法使用第一个有效组合获得重载,因为可能没有。

我知道这个问题的确不是很好,但是找不到任何具体要点可以做得更好。我会根据您的喜好编辑问题以获取更多信息。

3 个答案:

答案 0 :(得分:2)

使用lambda而不是原始函数指针以及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

答案 1 :(得分:0)

不确定这是问题的关键,但是如果这条指令

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

是尝试将具有特定签名的foobar()函数的指针更改为具有相同foobar()名称但具有不同签名的函数的指针...根本无法工作:指向函数的指针是指向函数的指针,你不能简单地将它转换为指向另一个函数的指针,希望拦截一个具有相同名称的函数,希望调用可以正常工作。

答案 2 :(得分:0)

删除此行:

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

你不想要一个指向函数的指针。您想要在一组操作数上调用一个函数,并且不需要指向函数的指针。

接下来,取代T& funcptrT&& 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) {/ 1}}。