voidを返す関数も対等に扱いたい。

```cpp:sample01.cpp
#include <string>
#include <iostream>

std::string get_functype(int) {
    return "You have returned an int value.";
}

std::string get_functype(double) {
    return "You have returned a double value.";
}

int int_func(void) {
    auto ret = 100;
    std::cout << "I will return " << ret << "." << std::endl;
    return ret;
}

double double_func(void) {
    auto ret = 3.14;
    std::cout << "I will return " << ret << "." << std::endl;
    return ret;
}

int main(void) {
    std::cout << get_functype(int_func()) << std::endl;
    std::cout << get_functype(double_func()) << std::endl;
    return 0;
}
```

これは普通にコンパイルして実行できる。

ありふれた関数のオーバーロード。

```text
I will return 100.
You have returned an int value.
I will return 3.14.
You have returned a double value.
```

ではこれは？

```cpp:sample02.cpp
#include <string>
#include <iostream>

std::string get_functype(int) {
    return "You have returned an int value.";
}

std::string get_functype(double) {
    return "You have returned a double value.";
}

std::string get_functype(void) {
    return "You have returned nothing.";
}

int int_func(void) {
    auto ret = 100;
    std::cout << "I will return " << ret << "." << std::endl;
    return ret;
}

double double_func(void) {
    auto ret = 3.14;
    std::cout << "I will return " << ret << "." << std::endl;
    return ret;
}

void void_func(void) {
    std::cout << "I will return nothing." << std::endl;
}

int main(void) {
    std::cout << get_functype(int_func()) << std::endl;
    std::cout << get_functype(double_func()) << std::endl;
    std::cout << get_functype(void_func()) << std::endl;
    return 0;
}
```

コンパイルできない。

```text
g++ -std=c++1y sample02.cpp -o sample02
sample02.cpp: 関数 ‘int main()’ 内:
sample02.cpp:35:42: エラー: void 式の無効な使用法です
     std::cout << get_functype(void_func()) << std::endl;
                                          ^
```

`void`を返す関数は、普通の関数みたいに戻り値の型で推論できない。

でも、これを対等に扱いたい。この（あるいは、これに近いコードを）コンパイルして実行できるようにしたいの。

で、

```cpp:sample03.cpp
#include <string>
#include <iostream>

std::string get_functype(int) {
    return "You have returned an int value.";
}

std::string get_functype(double) {
    return "You have returned a double value.";
}

std::string get_functype(void) {
    return "You have returned nothing.";
}

int int_func(void) {
    auto ret = 100;
    std::cout << "I will return " << ret << "." << std::endl;
    return ret;
}

double double_func(void) {
    auto ret = 3.14;
    std::cout << "I will return " << ret << "." << std::endl;
    return ret;
}

void void_func(void) {
    std::cout << "I will return nothing." << std::endl;
}


template<typename RET>
inline auto get_functype_switch_helper(RET(*func)(void)) {
    return get_functype(func());
}

template<>
inline auto get_functype_switch_helper<void>(void(*func)(void)) {
    func();
    return get_functype();
}

template<typename FUNC>
inline auto get_functype_switch(FUNC func) {
    return get_functype_switch_helper<decltype(func())>(func);
}


int main(void) {
    std::cout << get_functype_switch(int_func) << std::endl;
    std::cout << get_functype_switch(double_func) << std::endl;
    std::cout << get_functype_switch(void_func) << std::endl;
    return 0;
}
```

2つのテンプレート関数を間に挟んで、めでたく解決。

```text
I will return 100.
You have returned an int value.
I will return 3.14.
You have returned a double value.
I will return nothing.
You have returned nothing.
```

ちょっと醜いけどｗｗ

インライン関数にしとけば、おそらく実行時のオーバーヘッドは極小か完全にゼロ。

ついでに、引数も自由に付けられるようにしたいよね。

```cpp:sample04.cpp
#include <string>
#include <iostream>

std::string get_functype(int) {
    return "You have returned an int value.";
}

std::string get_functype(double) {
    return "You have returned a double value.";
}

std::string get_functype(void) {
    return "You have returned nothing.";
}

int int_func(int n1, int n2) {
    auto ret = n1 + n2;
    std::cout << "I will return " << ret << "." << std::endl;
    return ret;
}

double double_func(double ret) {
    std::cout << "I will return " << ret << "." << std::endl;
    return ret;
}

void void_func(void) {
    std::cout << "I will return nothing." << std::endl;
}


template<typename RET>
struct get_functype_switch_helper{
    template<typename... ARGS>
    static auto x(RET(*func)(ARGS...), ARGS... args) {
        return get_functype(func(args...));
    }
};

template<>
struct get_functype_switch_helper<void>{
    template<typename... ARGS>
    static auto x(void(*func)(ARGS...), ARGS... args) {
        func(args...);
        return get_functype();
    }
};

template<typename FUNC, typename... ARGS>
inline auto get_functype_switch(FUNC func, ARGS... args) {
    return get_functype_switch_helper<decltype(func(args...))>::template x<ARGS...>(func, args...);
}


int main(void) {
    std::cout << get_functype_switch(int_func, 30, 70) << std::endl;
    std::cout << get_functype_switch(double_func, 3.14) << std::endl;
    std::cout << get_functype_switch(void_func) << std::endl;
    return 0;
}
```

これでOK。

可変長テンプレートと構造体を使った関数テンプレートの部分特殊化ハックで、さらにカオスな感じになってきたｗ

でも、こういうケースが出現するたびに、いちいちこんなの書くの面倒だし、、

こんなときは、

伝統の、

マクロｗｗ

```cpp:void_switch.h
#ifndef INCLUDED_VOID_SWITCH_H
#define INCLUDED_VOID_SWITCH_H

#define DECLARE_VOID_SWITCH(func1)                                               \
template<typename RET>                                                           \
struct func1##_switch_helper{                                                    \
    template<typename... ARGS>                                                   \
    static auto x(RET(*func2)(ARGS...), ARGS... args) {                          \
        return func1(func2(args...));                                            \
    }                                                                            \
};                                                                               \
                                                                                 \
template<>                                                                       \
struct func1##_switch_helper<void>{                                              \
    template<typename... ARGS>                                                   \
    static auto x(void(*func2)(ARGS...), ARGS... args) {                         \
        func2(args...);                                                          \
        return func1();                                                          \
    }                                                                            \
};                                                                               \
                                                                                 \
template<typename FUNC, typename... ARGS>                                        \
inline auto func1##_switch(FUNC func2, ARGS... args) {                           \
    return func1##_switch_helper<decltype(func2(args...))>                       \
        ::template x<ARGS...>(func2, args...);                                   \
}                                                                                \


#endif
```

```cpp:sample05.cpp
#include <string>
#include <iostream>
#include "void_switch.h"

std::string get_functype(int) {
    return "You have returned an int value.";
}

std::string get_functype(double) {
    return "You have returned a double value.";
}

std::string get_functype(void) {
    return "You have returned nothing.";
}

int int_func(int n1, int n2) {
    auto ret = n1 + n2;
    std::cout << "I will return " << ret << "." << std::endl;
    return ret;
}

double double_func(double ret) {
    std::cout << "I will return " << ret << "." << std::endl;
    return ret;
}

void void_func(void) {
    std::cout << "I will return nothing." << std::endl;
}

DECLARE_VOID_SWITCH(get_functype)

int main(void) {
    std::cout << get_functype_switch(int_func, 30, 70) << std::endl;
    std::cout << get_functype_switch(double_func, 3.14) << std::endl;
    std::cout << get_functype_switch(void_func) << std::endl;
    return 0;
}
```

醜いマクロ宣言はヘッダファイルに追い出して、コードもスッキリ。再利用もできる。

めでたしめでたし。

※途中のテンプレート関数呼び出しで、テンプレートパラメータを引き継ぐように若干修正。