贡献者: addis
<>
声明 template 类型)。也就是本来 add(long long a, long long b)
调用的时候可以用很多不同类型的参数,进行自动转换,现在都不行了,每套不同的参数都会被编译器生成具体的函数。
<>
至少声明 return type
<>
声明 template parameter 的时候, 可以只声明前几个, 把剩下的留给编译器 deduce.
using <Base>::<fun>
才可以使用 Base class template 中的 overload 函数.
if constexpr
加上 <typetrait>
可以对不同的类型执行不同的代码 (没有 overhead).
对整型模板参数循环(C++ 17):
#include <iostream>
template<int Start, int Step, int End>
void constexprLoop() {
if constexpr (Start < End) {
// ==== 循环体 ====
cout << Start << endl;
// ===============
constexprLoop<Start + Step, Step, End>();
}
}
int main() {
constexprLoop<0, 2, 6>();
return 0;
}
不会有任何性能损失,cout
大概率会被 inline。
更直接的,还可以用 constexpr
函数
constexpr int factorial(int n) {
int result = 1;
for (int i = 2; i <= n; ++i) {
result *= i;
}
return result;
}
但是别高兴得太早,这个函数要求能 100% 在编译时执行(虽然运行时也能执行,但输出就不是 constexpr
了)。所以别想用它来给 tuple
写一个循环。
另见 SLISC
中如何实现 std::hash<tuple<...>>
。
【这里的笔记过时了,用 SFINAE 就好】 在普通的 function overloading 的基础上:
T *
和 vector <T>
肯定比 T
更 specialized. 猜测大概是能接受的变量类型越少越 specialize.
if constexpr
加上 <typetrait>
可以对不同的类型执行不同的代码 (没有 overhead).
<typetrait>
里面有用的模板有 is_float<T>
, is_same<T1, T2>
template <class T, class T1>
inline void divide_equals_vs(T *v, const T1 &s, Long_I N)
{
constexpr std::is_floating_point<T> is_float;
if constexpr (is_float) {
times_equals_vs(v, 1./s, N);
}
else {
for (Long i = 0; i < N; ++i)
v[i] /= s;
}
}
constexpr
函数和 constructor 会自动 inline, 即可以无视 ODR(one definition rule).
if constexpr()
是编译时完成的, 相当于 #ifdef
, #endif
导致的条件编译, 所以没有编译到的部分即使对当前的情况有语法错误也没有关系. 例如下面这段 SLISC 中的代码, 当 T1, T2 是 Vector<>
或 Matrix<>
的时候, 即使 dim1()
, dim2()
, dim3()
没有定义也不会出错!
template <class T1, class T2>
Bool shape_cmp(const T1 &v1, const T2 &v2)
{
if constexpr (T1::ndims() == 1 && T2::ndims() == 1) {
return v1.size() == v2.size();
}
else if constexpr (T1::ndims() == 2 && T2::ndims() == 2) {
return v1.nrows() == v2.nrows() && v1.ncols() == v2.ncols();
}
else if constexpr (T1::ndims() == 3 && T2::ndims() == 3) {
return v1.dim1() == v2.dim1() && v1.dim2() == v2.dim2()
&& v1.dim3() == v2.dim3();
}
return false;
}
enum{};
的做法完全可以被 static constexpr
函数取代.
constexpr long myfac(long i)
{
if (i == 0)
return 1;
return myfac(i - 1)*i;
}
int main()
{
constexpr long i = myfac(4);
int a[i]; // totally ok!
long j = 5;
long k = myfac(j); // still ok!
}
std::common_type<T1, T2, ...>::type
返回一个共同的类型 T
使得所有的 T1, T2...
都可以 implicitly 转换成 T
. 例如可以定义两种类型的加法为
template <class T1, class T2>
std::common_type<T1, T2, ...>::type myplus(const T1 &x, const T2 &y)
{
return x + y;
}
该函数 argument 如果输入 complex <double>
和 double
就可以返回前者, 输入 double
和 int
也可以返回前者.
...
variadic template lambda
template<typename Func, typename... Args>
auto callGenericLambda(Func&& func, Args&&... args) -> decltype(auto) {
return func(std::forward<Args>(args)...);
}
int main() {
auto lambda = [](auto&&... args) {
// A fold expression to print all arguments.
((std::cout << args << ' '), ...);
};
callGenericLambda(lambda, 42, "Hello", 3.14);
}