我试图将一个函数的调用包装到另一个函数中。 我可以传递函数指针或使用非类型模板参数直接调用函数(通过 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
}
我的用例是实现“难以置信的快速代表”。 我希望它们能够高效且无缝地处理全局函数和函数指针。
我已经尝试过:
这是编译时信息,为什么我被迫在 <> 和 () 之间手动选择? 这是语言语法的限制吗?
经过多次实验,我找到了解决方案。
问题在于 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);
}