C++ 在传递编译时与运行时已知的函数指针时是否可以使用一致的语法?

问题描述 投票:0回答:1

我试图将一个函数的调用包装到另一个函数中。 我可以传递函数指针或使用非类型模板参数直接调用函数(通过 constexpr 函数指针)。

using FunctionPtr = void(*)();

void foo(){}           // Function. Known at compile time
FunctionPtr bar = foo; // Function pointer. Set at runtime from a dll for example

// In C++ one may pass a function pointer as a value template
template<FunctionPtr function> void impl()
{
    function(); // (Optimal) Known at compile time
}

// Or pass at runtime
void impl(FunctionPtr function)
{
    function(); // Known at runtime. (*Might* be optimised or not)
}

int main()
{
    impl<foo>(); // Good. Compile time
    impl(foo);   // Bad. I should have called impl<foo>()
    impl(bar);   // Good. Runtime but syntax is different
    impl<bar>(); // Bad. Fails to compile

// Psudocode for desired result
    #define BIND(x) (is_function<decltype(x)> ? impl<x>() : impl(x))
    BIND(foo);
    BIND(bar);
    // This does not work with std::is_function_v() because of the compiler error when passing a function pointer in the impl<x>() case
}

我的用例是实现“难以置信的快速代表”。 我希望它们能够高效且无缝地处理全局函数和函数指针。

我已经尝试过:

  • 模板
  • constexpr 函数指针
  • 如果 constexpr()
  • 保守
  • if consteval() // c++23

这是编译时信息,为什么我被迫在 <> 和 () 之间手动选择? 这是语言语法的限制吗?

相关:C++ 检查 if 语句可以被 constexpr 计算

c++ function syntax delegates
1个回答
0
投票

经过多次实验,我找到了解决方案。

问题在于 C++ 缺少 pass by constexpr。 这就是为什么您被迫使用模板值来处理不一致的语法! 传递运行时值将无法编译值模板。

但是,您可以通过使用可以返回 constexpr 值的 lambda 来解决此问题 (C++17)

solution([&](){return foo;});

第二个技巧是使用 if constexpr() ,如果未将其实例化为模板的一部分,它将丢弃未使用的分支。 因此,分支必须依赖于 lambda 包装器的类型并且是 constexpr 语句。

使用 C++20 requires 语句,我们可以测试替换是否匹配,更好的是,如果不编译,它会被忽略!例如,当我们将运行时值传递给编译时值模板时。

template<typename Lam> void solution(Lam lam)
{
    // Negative branch is discarded due to template dependency
    // Requires guards against the statement not compiling
    if constexpr(requires{foo<lam()>();})
    {
        impl<lam()>(); // Constexpr Value
    }
    else
    {
        impl(lam()); // Normal value
    }
}

#define BIND(x) ( solution([&](){return x;}) )
int main()
{
    // Consistent syntax and picks the best option
    BIND(foo);
    BIND(bar);

    Function fn = bar;
    BIND(fn);
}

有人提议在语言中添加 pass by constexpr

© www.soinside.com 2019 - 2024. All rights reserved.