如何编写只能接收 int 或 float 指针的 lambda 函数?
How to write a lambda function that can only take in int or float pointers?
我需要创建一个可以接收 int *
或 float *
的 lambda 函数,例如
auto func = [](void* ptr) {
// do some assignments with the pointer
}
目前,我正在使用 void *
方法,但我想知道还有哪些其他方法可以实现我想要的?
我无法访问我的代码库中的 C++17 功能,因此必须坚持使用 C++14 或更低的语义。
C++14 具有通用的 lambda,这意味着您可以在它们上使用 SFINAE,例如在他们尾随的 return 类型中:
#include <type_traits>
template <typename T> struct valid_ptr_type : std::false_type {};
template <> struct valid_ptr_type<int *> : std::true_type {};
template <> struct valid_ptr_type<float *> : std::true_type {};
template <typename T> constexpr bool valid_ptr_type_v{valid_ptr_type<T>::value};
int main() {
// only allow ptr args that fulfills
// the valid_ptr_type_v<decltype(ptr)> trait
auto func = [](auto *ptr) ->
std::enable_if_t<valid_ptr_type_v<decltype(ptr)>> {
// do stuff with ptr
}; // note: void return type (std::enable_if default)
int a{};
float b{};
char c{};
func(&a);
func(&b);
// func(&c); // error
}
这背后的作用是约束 lambda 闭包类型的模板函数调用运算符的推导单个模板参数。
// ~ish
struct AnonClosureTypeOfGenericLambda {
template <typename T,
typename = std::enable_if_t<valid_ptr_type_v<decltype(T*)>>>
void operator()(T* ptr) const { /* ... */ }
};
我推荐使用 static_assert
代码清晰,编译错误。此外,虽然不是问题,但由于这两种类型都是浮点数或整数的指针,您可以使用条件根据实际类型进行不同的计算。
#include <type_traits>
int main()
{
auto foo = [](auto p) {
static_assert(std::is_same_v<decltype(p), float*> || std::is_same_v<decltype(p), int*>);
if (std::is_same_v<decltype(p), int*>)
*p = 42;
else
*p = 42.1f;
};
float f{};
int i{};
double d{};
// compiles
foo(&f);
foo(&i);
// doesn't compile
//foo(&d);
}
通过使用 lambda 重载技巧:
template<typename... Ts> struct overload : public Ts... { using Ts::operator()...; };
template<typename... Ts> overload(Ts...)->overload<Ts...>;
auto f = overload([](int *) { /* do something with int-pointer */ }
, [](float *){ /* do something with void-pointer */ });
但那是 C++17。这是 C++11 的解决方案:
template <class... Fs>
struct overload_t;
template <typename F, typename ... Fs>
struct overload_t<F, Fs...> : F, overload_t<Fs...>
{
overload_t(F f, Fs... fs) : F(std::move(f)), overload_t<Fs...>(std::move(fs)...) {}
using F::operator();
using overload_t<Fs...>::operator();
};
template <typename F>
struct overload_t<F> : F
{
overload_t(F f) : F(std::move(f)) {}
using F::operator();
};
template <typename... Fs>
overload_t<Fs...> overload(Fs... fs)
{
return overload_t<Fs...>(std::move(fs)...);
}
我需要创建一个可以接收 int *
或 float *
的 lambda 函数,例如
auto func = [](void* ptr) {
// do some assignments with the pointer
}
目前,我正在使用 void *
方法,但我想知道还有哪些其他方法可以实现我想要的?
我无法访问我的代码库中的 C++17 功能,因此必须坚持使用 C++14 或更低的语义。
C++14 具有通用的 lambda,这意味着您可以在它们上使用 SFINAE,例如在他们尾随的 return 类型中:
#include <type_traits>
template <typename T> struct valid_ptr_type : std::false_type {};
template <> struct valid_ptr_type<int *> : std::true_type {};
template <> struct valid_ptr_type<float *> : std::true_type {};
template <typename T> constexpr bool valid_ptr_type_v{valid_ptr_type<T>::value};
int main() {
// only allow ptr args that fulfills
// the valid_ptr_type_v<decltype(ptr)> trait
auto func = [](auto *ptr) ->
std::enable_if_t<valid_ptr_type_v<decltype(ptr)>> {
// do stuff with ptr
}; // note: void return type (std::enable_if default)
int a{};
float b{};
char c{};
func(&a);
func(&b);
// func(&c); // error
}
这背后的作用是约束 lambda 闭包类型的模板函数调用运算符的推导单个模板参数。
// ~ish
struct AnonClosureTypeOfGenericLambda {
template <typename T,
typename = std::enable_if_t<valid_ptr_type_v<decltype(T*)>>>
void operator()(T* ptr) const { /* ... */ }
};
我推荐使用 static_assert
代码清晰,编译错误。此外,虽然不是问题,但由于这两种类型都是浮点数或整数的指针,您可以使用条件根据实际类型进行不同的计算。
#include <type_traits>
int main()
{
auto foo = [](auto p) {
static_assert(std::is_same_v<decltype(p), float*> || std::is_same_v<decltype(p), int*>);
if (std::is_same_v<decltype(p), int*>)
*p = 42;
else
*p = 42.1f;
};
float f{};
int i{};
double d{};
// compiles
foo(&f);
foo(&i);
// doesn't compile
//foo(&d);
}
通过使用 lambda 重载技巧:
template<typename... Ts> struct overload : public Ts... { using Ts::operator()...; };
template<typename... Ts> overload(Ts...)->overload<Ts...>;
auto f = overload([](int *) { /* do something with int-pointer */ }
, [](float *){ /* do something with void-pointer */ });
但那是 C++17。这是 C++11 的解决方案:
template <class... Fs>
struct overload_t;
template <typename F, typename ... Fs>
struct overload_t<F, Fs...> : F, overload_t<Fs...>
{
overload_t(F f, Fs... fs) : F(std::move(f)), overload_t<Fs...>(std::move(fs)...) {}
using F::operator();
using overload_t<Fs...>::operator();
};
template <typename F>
struct overload_t<F> : F
{
overload_t(F f) : F(std::move(f)) {}
using F::operator();
};
template <typename... Fs>
overload_t<Fs...> overload(Fs... fs)
{
return overload_t<Fs...>(std::move(fs)...);
}