以下(学术构建的,非工作)代码有两个"问题",我知道如何以丑陋的方式解决。我想要一个漂亮的。
#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);
}
- 显然,如果函数
brol()
,我无法在内部构建Integer
和Floating
,因为static_asserts。这个问题可以通过SFINAE测试轻松解决,无论是用std::enable_if_v
还是一些... -> decltype( ... )
技巧。同样,我也可以改进函数体的结尾并避免if/else块 - 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);
但仍然是您必须定义的问题 i
或 f
.
目前还不清楚你的Integer
和Floating
的目的是什么......
但是关于 " 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);
}