C++ 专门针对特定类型的 lambda
C++ specialize a lambda for a certain type
我一直在研究 here 中介绍的 lambda "overloading",很快就发现创建专门的 lambda 闭包很方便。所以我首先试错了一点,我最有希望的试验是
auto call_for_vector = [] template<typename T> (std::vector<T>) {};
但是,稍后查看 cppreference 表明标准似乎都不允许这种构造或类似构造。
不支持此类专业化的原因是什么?
我知道可以使用 SFINAE 获得这种行为,但它的可读性较差,难以编写且更容易出错。当然也可以简单地写一个 class 和一个适当的 operator()
,但这就是 C++03 :-)
这样的语法有什么用?:
一个示例,这将允许一个简单的 lambda "overload",如以下代码
template <class F1, class F2>
struct overload_set : F1, F2
{
overload_set(F1 x1, F2 x2) : F1(x1), F2(x2) {}
using F1::operator();
using F2::operator();
};
template <class F1, class F2>
overload_set<F1,F2> overload(F1 x1, F2 x2)
{
return overload_set<F1,F2>(x1,x2);
}
auto f = overload(
[](auto&& x){ std::cout<<"call by default"<<std::endl;},
[] template<typename T>(std::vector<T>){std::cout<<"call for vector"<<std::endl;}
);
一个人可以获得这种行为,例如通过使用基于 this answer 中的技术的 SFINAE,但同样......这很糟糕。
是否有 SFINAE 获取特定重载的简单解决方法?
这种类型的编码乍一看似乎是多余的,但我们可以利用一些不错的特性。关于您提到的 post,我计划在第 2 部分中展示一种简洁的方法 检查类型是否具有特定成员 (函数或数据) .假设您想检查 serialize
成员函数;而不是使用复杂的机制,我发现它变得如此简单:
auto hs = overload(
[ ](auto&& x) -> decltype(x.serialize(2), std::true_type{}) {
return{}; }, // ^^ this guy ^^
[ ](...) -> std::false_type { return {}; });
可以找到标准演变的细节 ,但我 post 编辑此文的原因是提倡这样一种语法,如果我们已经拥有它,上述内容可能是 扩展到允许"overloaded"通用lambdas之间的部分排序:
auto do_something = overload(
[ ]<class X>(shared_ptr<X> x) -> decltype(x.serialize(2), std::true_type{}) {
/*do something specific for shared ptrs of X */ return{}; },
[ ]<class X>(X& x) -> decltype(x.serialize(2), std::true_type{}) {
/*do a generic operation for other types that have serialize*/return{}; },
[ ](...) -> std::false_type { /*do nothing*/ return {}; });
我一直在研究 here 中介绍的 lambda "overloading",很快就发现创建专门的 lambda 闭包很方便。所以我首先试错了一点,我最有希望的试验是
auto call_for_vector = [] template<typename T> (std::vector<T>) {};
但是,稍后查看 cppreference 表明标准似乎都不允许这种构造或类似构造。
不支持此类专业化的原因是什么?
我知道可以使用 SFINAE 获得这种行为,但它的可读性较差,难以编写且更容易出错。当然也可以简单地写一个 class 和一个适当的 operator()
,但这就是 C++03 :-)
这样的语法有什么用?:
一个示例,这将允许一个简单的 lambda "overload",如以下代码
template <class F1, class F2>
struct overload_set : F1, F2
{
overload_set(F1 x1, F2 x2) : F1(x1), F2(x2) {}
using F1::operator();
using F2::operator();
};
template <class F1, class F2>
overload_set<F1,F2> overload(F1 x1, F2 x2)
{
return overload_set<F1,F2>(x1,x2);
}
auto f = overload(
[](auto&& x){ std::cout<<"call by default"<<std::endl;},
[] template<typename T>(std::vector<T>){std::cout<<"call for vector"<<std::endl;}
);
一个人可以获得这种行为,例如通过使用基于 this answer 中的技术的 SFINAE,但同样......这很糟糕。
是否有 SFINAE 获取特定重载的简单解决方法?
这种类型的编码乍一看似乎是多余的,但我们可以利用一些不错的特性。关于您提到的 post,我计划在第 2 部分中展示一种简洁的方法 检查类型是否具有特定成员 (函数或数据) .假设您想检查 serialize
成员函数;而不是使用复杂的机制,我发现它变得如此简单:
auto hs = overload(
[ ](auto&& x) -> decltype(x.serialize(2), std::true_type{}) {
return{}; }, // ^^ this guy ^^
[ ](...) -> std::false_type { return {}; });
可以找到标准演变的细节
auto do_something = overload(
[ ]<class X>(shared_ptr<X> x) -> decltype(x.serialize(2), std::true_type{}) {
/*do something specific for shared ptrs of X */ return{}; },
[ ]<class X>(X& x) -> decltype(x.serialize(2), std::true_type{}) {
/*do a generic operation for other types that have serialize*/return{}; },
[ ](...) -> std::false_type { /*do nothing*/ return {}; });