21

私はこれを本当に理解していません。コンパイラは最初に中かっこで囲まれたものを実行し、次にその結果を最も適切な関数に与えると思いました。ここでは、それを処理するための初期化子リストを関数に提供しているように見えます...

#include <string>
#include <vector>
using namespace std;

void func(vector<string> v) { }

void func(vector<wstring> v) { }

int main() {
  func({"apple", "banana"});
}

エラー:

<stdin>: In function 'int main()':
<stdin>:11:27: error: call of overloaded 'func(<brace-enclosed initializer list>)' is ambiguous
<stdin>:11:27: note: candidates are:
<stdin>:6:6: note: void func(std::vector<std::basic_string<char> >)
<stdin>:8:6: note: void func(std::vector<std::basic_string<wchar_t> >)

func(vector<string> v)オーバーロードが呼び出されないのはなぜですか。そうすることはできますか?

4

1 に答える 1

25

これは微妙でした。

std::vector2つの範囲イテレータを使用するコンストラクタがあります。これはテンプレートコンストラクターです(C ++ 11標準の23.6.6.2で定義されています)。

template<typename InputIterator>
vector(InputIterator first, InputIterator last, 
const allocator_type& a = allocator_type());

std::vector<wstring>これで、を受け入れる構成要素はinitializer_list、関数呼び出しでの暗黙の変換とは一致しません(const char*タイプstringは異なります)。ただし、上記の1つは、もちろん、std::vector<string>との両方に含まれていますが、と推定できるstd::vector<wstring>ため、完全に一致する可能性があります。推定されたテンプレート引数が実際にベクトルの基になる型の概念を満たしているかどうかを確認するために何らかのSFINAE手法が使用されない限り(これは私たちの場合ではありません)、このコンストラクターは実行可能です。InputIteratorconst char*InputIterator

しかし、繰り返しになりますが、両方ともstd::vector<string>std::vector<wstring>ブレースされた初期化子リストからの変換を実現する実行可能なコンストラクターを持っています。したがって、あいまいさです。

したがって、問題は、実際にはイテレータ(*)では"apple"あり"banana"ませんが、最終的にはそのように表示されるという事実にあります。関数呼び出しに引数を1つ追加する"joe"と、呼び出しの曖昧さが解消され、コンパイラーは範囲ベースのコンストラクターを除外し、実行可能な変換のみを選択するため、問題が修正されます(に変換できないため、実行可能でinitializer_list<wstring>ありません)。const char*wstring


*実際には、これらはへのポインタであるため、文字const charの定数イテレータと見なすこともできますが、テンプレートコンストラクタが考えているように、文字列の場合は間違いありません。

于 2013-01-29T17:34:09.233 に答える