I have just discovered the following technique. It looks very close to one of proposed concepts syntax, works perfectly on Clang, GCC and MSVC.
template
It works and allowed because it relays on widely used C++ features allowed by the standard:
SFINAE in function parameters ([temp.over]/1, [temp.deduct]/6, [temp.deduct]/8):
template
void foo(T&& v, typename std::enable_if::value>::type* = nullptr)
{ /* ... */ }
we cannot deduce on the actual parameter like void foo(typename std::enable_if
(CWG#549), but it is possible to workaround this limitation with template aliases (it is the trick I have presented in my question)
SFINAE in template parameter declaration ([temp.deduct]/7):
template ::value>::type* = nullptr>
void foo(T&& v)
{ /* ... */ }
Alias templates in function parameters ([temp.alias]/2):
template struct Alloc { /* ... */ };
template using Vec = vector>;
template
void process(Vec& v)
{ /* ... */ }
Alias templates can have default parameters ([temp.param]/12, [temp.param]/15, [temp.param]/18)
Template parameters of alias templates parameterized with deducible types still can be deduced ([temp.deduct.type]/17):
I have accepted @Barry's answer and put this one (with concentrated info and about every aspect the trick uses) because a lot of people (including me) are scared of C++ standard voodoo language about template deduction stuff.