web-dev-qa-db-ja.com

テンプレートの特殊化とenable_ifの問題

Enable_ifとテンプレートの特殊化の適切な使用法に関して問題が発生しています。

(機密保持の理由で)例を変更した後、以下に比較可能な例を示します。

1番目の引数が2番目の引数よりも小さいかどうかをチェックする「less」という関数があります。入力のタイプに応じて、2種類の実装が必要だとします。1つは整数用、もう1つはdouble用です。

私がこれまでに持っているコードは次のようになります-

#include <type_traits>
#include <iostream>

template <class T,
          class = typename std::enable_if<std::is_floating_point<T>::value>::type>
     bool less(T a, T b) {
  // ....
}

template <class T,
          class = typename std::enable_if<std::is_integral<T>::value>::type>
     bool less(T a, T b) {
  // ....
}

int main() {
    float a;
    float b;
    less(a,b);
    return 0;
}

上記のコードはコンパイルされません。理由は-lessメソッドを再定義していることを示しています。

エラーは次のとおりです。

Z.cpp:15:19: error: template parameter redefines default argument
          class = typename std::enable_if<std::is_integral<T>::value>::type>

                  ^
Z.cpp:9:19: note: previous default template argument defined here
          class = typename std::enable_if<std::is_floating_point<T>::value>::type>
                  ^

Z.cpp:16:11: error: redefinition of 'less'
     bool less(T a, T b) {
          ^

Z.cpp:10:11: note: previous definition is here
     bool less(T a, T b) {
          ^

Z.cpp:23:5: error: no matching function for call to 'less'
    less(a,b);
    ^~~~

Z.cpp:15:43: note: candidate template ignored: disabled by 'enable_if'
      [with T = float]
          class = typename std::enable_if<std::is_integral<T>::value>::type>
                                          ^
3 errors generated.

誰かがここで何が間違っているのか指摘できますか?

18
user855

デフォルトのテンプレート引数は、関数テンプレートの署名の一部ではありません。したがって、あなたの例では、lessの2つの同一のオーバーロードがあります。これは違法です。 clangはデフォルト引数の再定義について文句を言います(これも§14.1/ 12 [temp.param]によれば違法です)が、gccは次のエラーメッセージを生成します:

エラー:「template<class T, class> bool less(T, T)」の再定義

エラーを修正するには、enable_if式をデフォルトの引数からダミーのテンプレートパラメータに移動します

template <class T,
          typename std::enable_if<std::is_floating_point<T>::value, int>::type* = nullptr>
     bool less(T a, T b) {
  // ....
}

template <class T,
          typename std::enable_if<std::is_integral<T>::value, int>::type* = nullptr>
     bool less(T a, T b) {
  // ....
}

もう1つのオプションは、戻り値の型にenable_ifを使用することですが、これは読みにくいと思います。

template <class T>
      typename std::enable_if<std::is_floating_point<T>::value, bool>::type 
      less(T a, T b) {
  // ....
}

template <class T>
     typename std::enable_if<std::is_integral<T>::value, bool>::type 
     less(T a, T b) {
  // ....
}
24
Praetorian