#include <bits/stdc++.h>
using namespace std;
int Min(int a, int b) {return a < b ? a : b;}
template<class T,int N,T (*fun)(T,T)> struct SparseTable{
int lg[N+10],n;
T f[21][N+10];
int pw(int x){return 1<<x;}
SparseTable():n(0){lg[0]=-1;}
void insert(T x){
f[0][++n]=x,lg[n]=lg[n>>1]+1;
for(int t=1;pw(t)<=n;t++){
int i=n-pw(t)+1;
f[t][i]=fun(f[t-1][i],f[t-1][i+pw(t-1)]);
}
}
T query(int l,int r){
int len=lg[r-l+1];
return fun(f[len][l],f[len][r-pw(len)+1]);
}
};
int main() {
SparseTable<int,100010, Min> t;//compile succussfully
// SparseTable<int,100010, min> t;//compile failed
return 0;
}
you can use this template
Thank you a lot! But I still want to know why compile failed by using std::min?
The function signatures of
std::min
are different.So is it necessary to write a function like Min in my code to make the function of min unique, not vague?
Almost correct
Check first line
sincere thanks!I know my error.
dang I really wanted this to work. But your template only works for passing in
std::min
,std::max
. You can't pass in some arbitrary function like bitwise and/or etc because of some weird pointer/reference error:In my code library, I prefer the following design for customization points when they need to be function-like:
The good thing about lambdas is that they're just objects, and function well with the rest of the language. Starting from C++20, the C++ STL has been moving towards making new functions niebloids (using mechanisms that disable ADL, and currently they seem to be only implemented as function objects) starting from range algorithms, so as I showed in the last example, it is possible to pass those as objects too. The one drawback is that you'd need
std::ranges::min
instead ofstd::min
which may or may not be extra typing, depending on whether you have a namespace alias forstd::ranges
.The correct term for things (in the STL) that we want is customization point object — and they behave like what their name advertises. They are somewhat stricter than what our requirements dictate, though, and for good reasons that I won't go into. Niebloids are a completely disjoint concept involved with disabling ADL. It is just that customization point objects tend to behave as niebloids by the standard specifications.
There's also a way to do this using an auto non-type template parameter for the lambda, but it doesn't work with lambdas that can't be called in a constexpr context (for example, lambdas that capture something).
Actually the error is quite normal, if you turn on the compiler error it shows
f2
is returning a reference, meanwhile(x & y)
is returning a temporary variable, so by the timef2
ends, the reference becomes dangling and pointing to some already gone variable.To pass some arbitrary function, you could change the template parameter to
template<class T, auto f = std::min<T> >
, and modify the parentheses operator toconst T operator()(size_t l, size_t r) const {
, andf2
toconst int f2(const int& x, const int& y)
, so it return by value. Of course, it might not be very optimal whenT
is a large object (but if your arbitrary function will create temporary its gonna be it anyway).