I want to do something like this:
T foo(uint8_t x)
if (x<32) return ((int32_t)1<<x);
else return ((int64_t)1<<x);
std::max(foo(10),some_variable); // return type of foo need to match some_variable
The return type of a function (even of a template function) — indeed, any expression, if I'm not mistaken, which is why Gill's answer doesn't solve anything — is a compile time attribute. What you want in your code is a run time decision. This is a fundamental clash which is not directly solvable (even a typedef wouldn't solve the contradiction, afaics).
What you can do is use some sort of handle or container. For example, you can always just return a 64 bit integer which is, in a sense, a base type for the shorter specializations (i.e. you can always cast a short int to a 64 bit int, but not necessarily vice versa).
You could also program something more sophisticated (big num class, polymorphic class, whatever), but the essence would be the same: The return type would be compile-time fixed, and the type would be able to somehow store all possible values, and have some run-time information about what "type" it actually is (if all values are integers, the run time information is the value itself), and possibly come with strongly typed conversion methods.