将SFINAE与通用lambda一起使用

Nik*_*iou 5 c++ lambda sfinae generic-lambda c++14

通用lambda可以利用"替换失败不是错误"规则吗?例

auto gL = 
    [](auto&& func, auto&& param1, auto&&... params) 
        -> enable_if_t< is_integral<
            std::decay_t<decltype(param1)>
        >::value>
    {
        // ...
    };

auto gL =  
     [](auto&& func, auto&& param1, auto&&... params) 
        -> enable_if_t< !is_integral<
            std::decay_t<decltype(param1)>
        >::value>
    {
        // ...
    };
Run Code Online (Sandbox Code Playgroud)

是否有任何变通方法或计划将其包含在语言中?此外,由于通用lambda是引擎盖下的模板化功能对象,这是不是有点奇怪,这是不能做到的?

Yak*_*ont 7

Lambdas是引擎盖下的功能对象.通用lambda是具有模板operator()s的函数对象.

template<class...Fs>
struct funcs_t{};

template<class F0, class...Fs>
struct funcs_t<F0, Fs...>: F0, funcs_t<Fs...> {
  funcs_t(F0 f0, Fs... fs):
    F0(std::move(f0)),
    funcs_t<Fs...>(std::move(fs)...)
  {}
  using F0::operator();
  using funcs_t<Fs...>::operator();
};
template<class F>
struct funcs_t<F>:F {
  funcs_t(F f):F(std::move(f)){};
  using F::operator();
};
template<class...Fs>
funcs_t< std::decay_t<Fs>... > funcs(Fs&&...fs) {
  return {std::forward<Fs>(fs)...};
}
Run Code Online (Sandbox Code Playgroud)

auto f_all = funcs( f1, f2 )生成一个对象,它是两者的过载f1f2.

auto g_integral = 
  [](auto&& func, auto&& param1, auto&&... params) 
    -> std::enable_if_t< std::is_integral<
        std::decay_t<decltype(param1)>
    >{}>
  {
    // ...
  };

auto g_not_integral =  
 [](auto&& func, auto&& param1, auto&&... params) 
    -> std::enable_if_t< !std::is_integral<
        std::decay_t<decltype(param1)>
    >{}>
{
    // ...
};

auto gL = funcs( g_not_integral, g_integral );
Run Code Online (Sandbox Code Playgroud)

并且调用gL将对两个lambda执行SFINAE友好重载决策.

上面做了一些虚假的动作,可以避免,在线性继承funcs_t.在工业质量库中,我可能会创建继承二进制而不是线性(以限制模板的实例化深度和继承树的深度).


顺便说一句,我知道SFINAE启用lambdas的原因有四个.

首先,使用new std::function,您可以在多个不同的回调签名上重载函数.

第二,上面的伎俩.

第三,讨论一个函数对象,它在它具有正确数量和类型的args时进行评估.

第四,自动元组拆包和类似.如果我正在使用延续传递样式,我可以询问传入的延续,如果它将接受解压缩的元组,或未来的非捆绑等.