14

次のコードは正常にコンパイルされます。

#include <string>

int dist(std::string& a, std::string& b) {
  return 0;
}

int main() {
  std::string a, b;
  dist(a, b);
  return 0;
}

しかし、関数の名前を dist から distance に変更すると:

#include <string>

int distance(std::string& a, std::string& b) {
  return 0;
}

int main() {
  std::string a, b;
  distance(a, b);
  return 0;
}

コンパイル時にこのエラーが発生します (gcc 4.2.1):

/usr/include/c++/4.2.1/bits/stl_iterator_base_types.h: In instantiation of ‘std::iterator_traits<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >’:
b.cpp:9:   instantiated from here
/usr/include/c++/4.2.1/bits/stl_iterator_base_types.h:129: error: no type named ‘iterator_category’ in ‘struct std::basic_string<char, std::char_traits<char>, std::allocator<char> >’

関数距離に名前を付けられないのはなぜですか?

4

1 に答える 1

23

その理由は、ADL (Argument Dependent Lookup) によって検出されるstd::distancestdと呼ばれる標準アルゴリズムが存在するためです。呼び出しは名前空間で修飾されていませんが、引数の型a(bつまりstd::string) は、std::distance関数 (つまりstd) であるため、std::distance()オーバーロードの解決についても考慮されます。

本当に関数を呼び出したい場合distance()(そうしないことをお勧めします)、それを自分の名前空間に配置してから、呼び出すときに関数名を完全修飾するか、グローバル名前空間に残して呼び出すことができますこのように:

    ::distance(a, b);
//  ^^

ただし、標準ライブラリの実装が の SFINAE 対応バージョンを提供している場合、ADL だけではプログラムのコンパイルが失敗しないiterator_traits可能性があることに注意してください(詳細については、この Q&A on StackOverflow - MooingDuckの好意による)。

の SFINAE フレンドリーな実装では、型 の引数が与えられた場合、戻り値の型が原因で、関数テンプレート (テンプレートであるため) をインスタンス化できないことiterator_traitsをコンパイラが認識する必要があります。std::distance()std::string

template< class InputIt >
typename std::iterator_traits<InputIt>::difference_type 
//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//       Trying to instantiate this with InputIt = std::string
//       may result in a soft error during type deduction if
//       your implementation is SFINAE-friendly, and in a hard
//       error otherwise.
    distance( InputIt first, InputIt last );

この場合、コンパイラは、オーバーロードの解決のためにこのテンプレートを単に破棄し、distance()関数を選択します。

ただし、標準ライブラリの実装が SFINAE に適したバージョンの を提供していない場合、SFINAE に適合iterator_traitsしないコンテキストで置換エラーが発生し、(ハード) コンパイル エラーが発生する可能性があります。

このライブの例では、GCC 4.8.0 でコンパイルする元のプログラムを示しています。これには、SFINAE に適しiterator_traitsた .

于 2013-06-03T17:17:13.410 に答える