C++14及更低版本如何编写仅接收int*或float*参数的lambda函数
C++14 兼容的替代实现方案
你当前使用的void*方案虽然可以实现需求,但没有编译期类型校验,一旦传入错误类型的指针,强转后访问会触发未定义行为。以下几个方案都可以实现仅接收int*/float*入参的效果,完全兼容C++14及更低版本:
- 方案1:泛型lambda + 编译期类型约束
C++14支持参数为auto的泛型lambda,可以配合类型萃取和静态断言做编译期校验,通用逻辑可以直接复用,不同类型的分支用标签分派实现,没有额外运行时开销:
#include <type_traits> // 定义允许传入的指针类型规则 template<typename T> struct is_valid_ptr : std::integral_constant<bool, std::is_same<T, int*>::value || std::is_same<T, float*>::value > {}; // 不同指针类型的分支处理逻辑 void handle_ptr(int* p, std::true_type /*int指针标记*/) { // int指针专属逻辑,例如 *p = 100; } void handle_ptr(float* p, std::false_type /*非int指针即float指针*/) { // float指针专属逻辑,例如 *p = 3.14f; } auto func = [](auto* ptr) { // 传入非法类型指针直接编译报错,不会留到运行时出问题 static_assert(is_valid_ptr<decltype(ptr)>::value, "Only int* or float* is allowed"); // int和float通用的逻辑可以直接写在此处,例如 *ptr += 1; 这类两种类型都支持的操作 // 需要区分类型的逻辑走标签分派 handle_ptr(ptr, std::is_same<decltype(ptr), int*>{}); };
这个方案零运行时开销、类型安全,适合两种指针大部分处理逻辑通用的场景。
- 方案2:带类型标签的指针包装类
如果指针类型是运行时动态确定的(例如根据输入配置决定传int还是float),可以实现一个轻量的可辨别联合包装指针,不需要模板元编程,调用时支持隐式转换:
struct NumPtr { enum Type { INT, FLOAT } tag; union { int* i_p; float* f_p; }; NumPtr(int* p) : tag(INT), i_p(p) {} NumPtr(float* p) : tag(FLOAT), f_p(p) {} }; auto func = [](const NumPtr& pw) { switch(pw.tag) { case NumPtr::INT: // 通过pw.i_p处理int指针逻辑 break; case NumPtr::FLOAT: // 通过pw.f_p处理float指针逻辑 break; } }; // 调用时直接传int*或float*即可,自动构造包装类 // int a = 1; func(&a); // float b = 2.0f; func(&b);
这个方案实现简单,运行时可以安全判断指针类型,不会出现void*强转错误的问题。
- 方案3:重载lambda集
如果两种指针的处理逻辑差异很大,没有可复用的通用代码,可以用重载集技巧,把两个分别处理int和float的lambda包装成一个可调用对象:
// C++14兼容的重载集基础实现,无C++17依赖 template<class F> struct overload_impl : F { overload_impl(F f) : F(f) {} using F::operator(); }; template<class F, class... Fs> struct overload_impl<F, Fs...> : F, overload_impl<Fs...> { overload_impl(F f, Fs... rest) : F(f), overload_impl<Fs...>(rest...) {} using F::operator(); using overload_impl<Fs...>::operator(); }; template<class... Fs> auto make_overload(Fs&&... fs) { return overload_impl<std::decay_t<Fs>...>(std::forward<Fs>(fs)...); } // 构造目标函数,两类指针的逻辑完全独立编写 auto func = make_overload( [](int* ptr) { // int指针全量处理逻辑 }, [](float* ptr) { // float指针全量处理逻辑 } );
这个方案不需要写额外的类型分派逻辑,传入其他类型指针会直接编译报错,适合两类指针处理逻辑完全独立的场景。
选型建议:优先选方案1,性能最好代码最简洁;如果是运行时动态确定指针类型选方案2;如果两类指针逻辑完全不重叠选方案3。原
void*方案仅建议在你能100%保证外部传参类型正确的场景下使用。
内容的提问来源于stack exchange,提问作者24n8
相关产品推荐
相关产品推荐

