1.The VA_ARGS traverse define, which only takes $$$O(logN)$$$ lines.
Normally to do this, you need to:
#define SP1(A) ...
#define SP2(A,B) ...
#define SP3(A,B,C) ...
...
Which is $$$O(N)$$$ defines. Here's an example supporting 31 or 32 (I forget) args using only $$$log32+5$$$ defines. Another 2 used for declaring a tool.
// O(logN) lines of __VA_ARGS__ traverse
#define SIZEOF_ARGS_H(...)SSIZEOF_ARGS_H(__VA_ARGS__,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,8,8,8,8,8,8,8,8,4,4,4,4,2,2,1)
#define SSIZEOF_ARGS_H($2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,N,...)N
#define CONCAT(a,b) CCONCAT(a,b)
#define CCONCAT(a,b) a##b
#define SP(A,B,...)CONCAT(SP,SIZEOF_ARGS_H(__VA_ARGS__))(A,B,__VA_ARGS__)
#define SP1(A,B,C)A(B,C)
#define SP2(A,B,C,D,...)A(B,C)A(B,D)__VA_OPT__(A(B,__VA_ARGS__))
#define SP4(A,B,C1,C2,C3,C4,...)SP2(A,B,C1,C2)SP2(A,B,C3,C4)__VA_OPT__(CONCAT(SP,SIZEOF_ARGS_H(__VA_ARGS__))(A,B,__VA_ARGS__))
#define SP8(A,B,C1,C2,C3,C4,C5,C6,C7,C8,...)SP4(A,B,C1,C2,C3,C4)SP4(A,B,C5,C6,C7,C8)__VA_OPT__(CONCAT(SP,SIZEOF_ARGS_H(__VA_ARGS__))(A,B,__VA_ARGS__))
#define SP16(A,B,C1,C2,C3,C4,C5,C6,C7,C8,C9,C10,C11,C12,C13,C14,C15,C16,...)SP8(A,B,C1,C2,C3,C4,C5,C6,C7,C8)SP8(A,B,C9,C10,C11,C12,C13,C14,C15,C16)__VA_OPT__(CONCAT(SP,SIZEOF_ARGS_H(__VA_ARGS__))(A,B,__VA_ARGS__))
// Classic usage of SP, to generate refs for struct members.
#define REFER(A,B)auto&B=A.B;
#define refer(A,...)SP(REFER,A,__VA_ARGS__)
// up to 31 or 32 Args available.
struct s{int a,b,c,d,e,f;}g;
int main(){
refer(g,a,b,c,d,e,f);
// expand to auto&a=g.a;auto&b=g.b;auto&c=g.c;......
a=0,b=0,c=0,d=0,e=0,f=0;
}
2. Auto min max
You need at least C++14 to use this.
The min max that can automatically infer the type of return value using common_type.
template<class a,size_t I=0,typename=void>struct d${using type=common_type_t<decltype(get<I>(declval<a>())),typename d$<a,I+1>::type>;};template<class a,size_t I>struct d$<a,I,enable_if_t<I==tuple_size<decay_t<a>>::value-1>>{using type=decltype(get<I>(declval<a>()));};
#define t$(A)[&]<size_t... I>(auto &u,index_sequence<I...>){typename d$<decltype(u)>::type ma=get<0>(u);((ma=A<decltype(ma)>(ma,get<I>(u))),...);return ma;}
#define min(...)({auto $$$=make_tuple(__VA_ARGS__);t$$$(min)($$$,make_index_sequence \lt tuple_size \lt decltype($$$)>::value>{});})
#define max(...)({auto $$$=make_tuple(__VA_ARGS__);t$$$(max)($$$,make_index_sequence \lt tuple_size \lt decltype($$$)>::value>{});})
The downside is it will call min(A, A) for once. For example min(1,2,3) will be min(min(min(1,1),2),3). Maybe it can be solved cleaner by using SP().
Note that common_type_t<A, A> == A. You can even put strings there as long as they're comparable.
Supports infinite args. After formatting it would look like this.
template<class a, size_t I = 0, typename = void>
struct d$
{
using type = common_type_t<decltype(get<I>(declval<a>())), typename d$<a, I + 1>::type>;
};
template<class a, size_t I>
struct d$<a, I, enable_if_t<I == tuple_size<decay_t<a>>::value - 1>>
{
using type = decltype(get<I>(declval<a>()));
};
#define t$(A) \
[&]<size_t... I>(auto &u, index_sequence<I...>) { \
typename d$<decltype(u)>::type ma = get<0>(u); \
((ma = A<decltype(ma)>(ma, get<I>(u))), ...); \
return ma; \
}
#define min(...) \
({ \
auto $ = make_tuple(__VA_ARGS__); \
t$(min)($$$, make_index_sequence \lt tuple_size \lt decltype($$$)>::value>{}); \
})
#define max(...) \
({ \
auto $ = make_tuple(__VA_ARGS__); \
t$(max)($$$, make_index_sequence \lt tuple_size \lt decltype($$$)>::value>{}); \
})
Example usages:
auto a=min(1,2ll,3.0f);
// decltype(a) == float, a=1.0f
auto b=min(string("1"),string("3"));
// b==string("1");
By the way I think there's space left for optimizing, I'm not a professional STL user, cannot figure out how tf does index_sequence come to work. I have been using these at least two months, so there's little chance that they have secret bugs.








Auto comment: topic has been updated by ForgottenCat (previous revision, new revision, compare).
you can just do min({1, 2, 3})
not when min({1ll, 2, 3}). i dislike <> things.
yeah tbh i hate that the compiler doesn't try casting int to ll
Their std::min max is just way too lazy for CP, I added these things so they can be casted automatically, after typing inf
min<ll>()s.