14

この質問は、 Issue with std::reference_wrapper に触発されています。たとえば、operator<forとしましょうstd::vector。関数テンプレートとして次のように定義されています

template< class T, class Alloc >
bool operator<( const vector<T,Alloc>& lhs,
                const vector<T,Alloc>& rhs );

その結果、関数引数から対応する関数パラメーターの型への暗黙的な変換は拒否されます (基本的にはテンプレートの性質のため)。これにより、 の有用性と利便性が大幅に低下しstd::reference_wrapperます。たとえば、std::sortonは使用できませんstd::vector<std::reference_wrapper<std::vector<int>>>

一方、すべての問題は、operator<が次のような非テンプレート Koenig 演算子として定義されている場合にのみ解決されます。

template <...>
class vector ... {
  friend bool operator<(const vector& a, const vector& b) {...}
};

なぜ標準ライブラリがこれではなく前者のアプローチを採用したのだろうか?

4

1 に答える 1

1

このコードを考えてみましょう (ああ):

template <class T>
class A {
  public:
  T m_x;

  friend bool operator<(const A & lhs, const A & rhs) {
    return lhs.m_x < rhs.m_x;
  }
};

そしてmain.cpp:

#include "A.h"

namespace buddy {
bool operator<(const A<double> & lhs, const A<double> &rhs) {
    return lhs.m_x > rhs.m_x;
};
}
using namespace buddy;
int main(int argc, char ** argv) {

  A<double> a1;
  A<double> a2;

  a1 < a2;

  return 0;
}

このコードはコンパイルされません:

main.cpp:14:5: エラー: 'operator<' のあいまいなオーバーロード (オペランドの型は 'A' と 'A') a1 < a2;

もちろん、両方の operator< が完全に一致するためです。一方、最初の operator< を (クラス外で定義された) に変更すると、次のようになります。

template <class T>
bool operator<(const A<T> & lhs, const A<T> & rhs) {
  return lhs.m_x < rhs.m_x;
}

コンパイラは不平を言うのをやめます: 完全一致と関数テンプレートの間の競合であるため、完全一致が使用されます。

operator< があなたが提案している方法で定義されている場合、std::vector のユーザーが operator< の動作を再定義する合理的な方法はありません。 .

結論として、標準の作成者は、特定の状況でより役立つかもしれない operator< を提供するよりも、operator< をオーバーロードしやすくすることを選択しました。彼らは正しい選択をしたと思います。

于 2015-05-15T20:30:40.050 に答える