处理重构、模板 SFINAE 测试和 lambda



以下(学术构建的,非工作)代码有两个"问题",我知道如何以丑陋的方式解决。我想要一个漂亮的。

#include <type_traits>
template<class T> struct Integer {
    Integer(T t) { static_assert(std::is_integral_v<T>, "Must be int"); }
};
template<class T> struct Floating {
    Floating(T t) { static_assert(std::is_floating_point_v<T>, "Must be flating point"); }
};
template<class T> void brol(T t)
{
    Integer i(t); //these two cannot work together
    Floating f(t); 
    template<class U> auto stuff = [] (U& u) -> void //invalid syntax : no template on bloc scope
    { u *= 2; } 
    if(std::is_integral_v<T>)
        stuff(i);
    else
        stuff(f);
}
int main()
{
    brol(2);
    brol(2.0);
}
  1. 显然,如果函数brol(),我无法在内部构建IntegerFloating,因为static_asserts。这个问题可以通过SFINAE测试轻松解决,无论是用std::enable_if_v还是一些... -> decltype( ... )技巧。同样,我也可以改进函数体的结尾并避免if/else块
  2. lambda stuff()不能是模板(因为编译器声明它不能)。我*可以*使其独立并将其隐藏在子命名空间中,但它不是那么好。

但是,我不能简单地用std::enable_if进行SFINAE测试,因为原型只会与默认模板参数不同,这是非法的(参见文档,std::enable_if中的注释部分)。

另一方面,我不知道如何很好地解决ussie 2...

在我看来

std::conditional应该解决你所有的问题

template <typename T>
void brol (T t)
 {
   using U = std::conditional_t<std::is_integral_v<T>, Integer<T>, Floating<T>>;
   U u{t};
   auto stuff = [] (U & u) -> void { u *= 2; };
   stuff(u);
 }

无论如何,lambda 的问题也可以用通用 lambda 来解决(正如 rustyx 所指出的)

   auto stuff = [] (auto & u) -> void { u *= 2; };

关于最终的if,在C++17中(您正在使用std::is_integral_v,因此您正在使用C++17),您也可以在类似情况下使用if constexpr

if constexpr (std::is_integral_v<T>)
    stuff(i);
else
    stuff(f);

但仍然是您必须定义的问题 if .

目前还不清楚你的IntegerFloating的目的是什么......

但是关于 " template<class U> auto stuff = [](U& u)" 部分,如果您简单地使用 auto 作为参数类型,C++14 确实会自动使 lambda 成为template

template<class T> void brol(T t) {
    auto stuff = [](auto& u)
    { u *= 2; };
    stuff(t);
}
int main() {
    brol(2);
    brol(2.0);
}

最新更新