If you don't want to do it without specialization, why not doing it with overload? ;) Specializing a function template is sometimes (no, often) a bad idea. With some SFINAE trick it wouldn't be difficult to create an overload that is selected only when those two conditions apply.
However, I already hear you shouting that it's not what you wanted to do: what you wanted is some kind of if inside of f() that would be executed in case the condition is true, and a corresponding else branch that would be executed when the condition is false.
However, notice that this would not be a static if, but a regular run-time if: in other words, the compiler would know at compile-time with 100% certainty that one of those two branches is never going to be executed (and it would probably issue an annoying warning about it), but it will have to parse both branches and prove them legal.
In practice, this means that you won't be able to put statements that depend on the particular type T (or on properties of T) in order to be compilable. For instance, in the code below compile_time_expression determines whether type T has a member function foo() or a member function bar():
T obj;
if (compile_time_expression)
{
obj.foo();
}
else
{
obj.bar();
}
However, the above won't compile if that particular T doesn't have both a member function foo() and a member function bar(): since what you have here is a run-time if, the compiler will have to parse both branches and make sure they're both compilable - and then possibly optimize away the one that is never going to be executed.
Unfortunately, C++ does not have any construct such as static if (yet?), so overloading + SFINAE is the right way to tackle this problem.
std::arrayhas a member functionempty(), which happens to be declaredconstexpr. Is that what you want?