_Generic

C11から導入された機能。なんというか、色々と面白い事に使えそうな感じの機能。タプルなんかと多分相性が良い。曲芸的濫用についてはまた今度考える。
ラムダ式オーバーロードする最も簡単な方法かもしれない。 http://melpon.org/wandbox/permlink/14pwv0Akg5DhrtnA

#include <iostream>

int main() {
    auto f = [](auto arg) {
        std::cout << _Generic(arg, int: arg + 1, double: arg - 1.0, default: arg) << std::endl;
    };
    f(1);
    f(1.5);
}

複数の型の組み合わせで分岐したい場合、1つにまとめるとなんとかなる。
caseに当たる部分にはcomplete typeが要求され、tag<int, int>:と書いてもテンプレートのインスタンス化が行われずにコンパイルエラーになったが、delctype(tag<int, int>{}):とワークアラウンドを書いたところうまく動いた。
http://melpon.org/wandbox/permlink/WpLjU1hyNgcUERUX

#include <iostream>

template <typename...> struct tag {};
    
template <typename T1, typename T2>
auto f(T1 arg1, T2 arg2) {
    std::cout << _Generic(tag<T1, T2>{}, decltype(tag<int, int>{}): arg1 * arg2, decltype(tag<double, double>{}): arg1 * arg2)
              << std::endl;
}

int main() {
    f(3, 5);
    f(1.5, 2.0);
}