🗂

C++14 で std::enable_if で fallback つきでクラスメソッドのオーバーロードしたいメモ

に公開2

C++14 で, テンプレート変数を取るクラスのメソッドで, 型に応じて異なる振る舞いをしたいが, fallback(指定した型以外を処理するデフォルトメソッド) もほしい.

とりあえず std::enable_if でいけるらしいが...

enable_if で分けたいときが 3 個以上あるとき...(2 個であれば enable_if と enable_if<!> でいけるため)

テンプレートなんもわからん...


template<class T>
class Bora {
 public:
   
   // dependent type が必要なので, V をでっちあげる
   template <typename V = T, std::enable_if_t<std::is_enum<V>::value, std::nullptr_t> = nullptr>
   bool dora() {
     std::cout << "enum type\n";
     return true
   }
   
   bool dora() {
     std::cout << "fallback\n";
     return false;
   }
}

のようにしても,

enum class Muda { Ari, Ora };

Bora<Muda> eb;
eb.dora();  // enum type を期待

Bora<int> ib;
ib.dora();  // fallback を期待

どちらも fallback のほうが呼ばれてしまいます.

fallback
fallback

解決

コメントで解決方法ご教示いただきました. ありがとうございます!

以下は元記事の記録用です.

とりあえずの解決1

ネットをあさってもあんまり情報ありません.
返り値が同じだとむりぽっそ?

返り値と引数を template 型にする必要がありますが, pxrUSD のコードで見つけた,
typename を返り値と引数で受け取るようにしてやるのがとりあえずの解決でしょうか...

   // dependant type が必要なので, V をでっちあげるのは引き続き必要
   template <typename V = T>
   typename std::enable_if<std::is_enum<V>::value, T>::value
   dora(T x) {
     std::cout << "enum type\n";
     return x;
   }
   
   // T dora(T x) だとエラーになるので注意
   template <typename V = T>
   V dora(V x) {
     std::cout << "fallback\n";
     return x;
   }

とりあえずの解決2

https://stackoverflow.com/questions/61526391/c-stdenable-if-fallback

にあるように, 判定をまとめるようにして, enable_if と enable_if<!> の二つになるようにする.

C++17

C++17 なら if constexpr で解決できるでしょう.

Discussion

山田(ymd)山田(ymd)

今回の件はコンパイル自体は通っていて、オーバーロード解決の優先順位の話だと思いますので、
ダミー引数を使って優先順位を操作する方法もあります。
(数値リテラルの解釈から int が優先される)

#include <iostream>
#include <type_traits>

template<class T>
class Bora {
   template <typename V = T, std::enable_if_t<std::is_enum<V>::value, std::nullptr_t> = nullptr>
   bool dora_impl(int) {
     std::cout << "enum type\n";
     return true;
   }

   bool dora_impl(char) {
     std::cout << "fallback\n";
     return false;
   }
 public:
    bool dora(){
        return this->dora_impl(0);
    }
};

enum class Muda { Ari, Ora };

int main(int argc, char** argv){
    Bora<Muda> eb;
    eb.dora();  // enum type

    Bora<int> ib;
    ib.dora();  // fallback

    return 0;
}

参考

https://yohhoy.hatenadiary.jp/entry/20190420/p1
https://qiita.com/pink_bangbi/items/023ea3b3fec28df5dcf4

syoyosyoyo

ありがとうございます!

ダミー引数必要ですが, スッキリ書けるのがいいですね. ダミー引数とってもいいようなケースではこちらで, メソッドシグネチャを変えたくないときは struct でのやり方でいきたいと思います.