1. ホーム
  2. c++

[解決済み] 関数シグネチャでstd::enable_ifを避けるべき理由

2022-04-30 06:55:39

質問

Scott Meyers からの投稿 コンテンツとステータス の、EC++11の次作についてです。 彼は、この本の中の1つの項目が、もしかしたら 避けるべきこと std::enable_if を関数シグネチャに使用することができます。 .

std::enable_if は、関数の引数、戻り値の型、クラステンプレートや関数テンプレートのパラメータとして使用し、条件付きで関数やクラスをオーバーロードの解決から除外することができます。

この質問 の3つの解答が全て表示されています。

関数のパラメータとして。

template<typename T>
struct Check1
{
   template<typename U = T>
   U read(typename std::enable_if<
          std::is_same<U, int>::value >::type* = 0) { return 42; }

   template<typename U = T>
   U read(typename std::enable_if<
          std::is_same<U, double>::value >::type* = 0) { return 3.14; }   
};

テンプレート・パラメータとして。

template<typename T>
struct Check2
{
   template<typename U = T, typename std::enable_if<
            std::is_same<U, int>::value, int>::type = 0>
   U read() { return 42; }

   template<typename U = T, typename std::enable_if<
            std::is_same<U, double>::value, int>::type = 0>
   U read() { return 3.14; }   
};

戻り値の型として。

template<typename T>
struct Check3
{
   template<typename U = T>
   typename std::enable_if<std::is_same<U, int>::value, U>::type read() {
      return 42;
   }

   template<typename U = T>
   typename std::enable_if<std::is_same<U, double>::value, U>::type read() {
      return 3.14;
   }   
};

  • どのソリューションを優先すべきか、なぜ他を避けるべきか?
  • どのような場合に 避けるべきこと std::enable_if を関数シグネチャで使用することができます。 は、戻り値の型(通常の関数シグネチャの一部ではなく、テンプレートの特殊化)として使用されることを懸念しているのでしょうか?
  • メンバー関数と非メンバー関数のテンプレートに違いはありますか?

解決方法は?

テンプレートパラメータにハックを入れる .

は、その enable_if をテンプレート・パラメータで使用する方法には、他の方法と比較して少なくとも2つの利点があります。

  • 可読性 enable_if の使用と戻り値/引数の型は、typename の曖昧さ回避と入れ子の型アクセスという厄介な塊に統合されません。曖昧さ回避と入れ子の型の混乱はエイリアス テンプレートで軽減できるとしても、無関係な 2 つのものを一緒に統合してしまうことになります。enable_ifの使用は、戻り値の型ではなく、テンプレートパラメータに関連しています。テンプレート・パラメータでそれらを持つことは、それらが重要なものに近いことを意味します。

  • ユニバーサル・アプリケ-ション : コンストラクタは戻り値の型を持たず、演算子は追加の引数を持てないものがあります。したがって、他の二つのオプションはどこでも適用できるわけではありません。テンプレートパラメータにenable_ifを指定すると、テンプレートでしかSFINAEを使用できないため、どこでも動作します。

私にとっては、可読性という点がこの選択の大きな原動力です。