web-dev-qa-db-ja.com

初期化リストの要素数が原因で、あいまいな呼び出しエラーが発生するのはなぜですか?

コンパイラによるdoSomethingの最初の2つの呼び出しはなぜ正常なのに、リスト内の2つの要素を使用するとあいまいな呼び出しが発生するのですか?

#include <vector>
#include <string>

void doSomething(const std::vector<std::string>& data) {}

void doSomething(const std::vector<int>& data) {}

int main(int argc, char *argv[])
{
    doSomething({"hello"}); // OK
    doSomething({"hello", "stack", "overflow"}); // OK
    doSomething({"hello", "stack"}); // C2668 'doSomething': ambiguous call

    return 0;
}
59
koolbanana

ここで何が起こっているかというと、2つの要素の初期化リストでは、両方の文字列リテラルがconst char*であるため、暗黙的にconst char[N]に変換できるということです。現在、std::vectorには、ポインターが修飾する2つのイテレーターをとるコンストラクターがあります。そのため、initializer_liststd::vector<std::string>コンストラクターは、std::vector<int>のイテレーター範囲コンストラクターと競合しています。

代わりにコードを変更すると

doSomething({"hello"s, "stack"s});

次に、初期化リストの要素はstd::stringsになり、あいまいさはなくなりました。

58
NathanOliver

引数が1つのリストと引数が3つのリストはどちらも、std::vector<std::string>std::initializer_listコンストラクターにのみ一致できます。ただし、2つの引数のリストは、std::vector<int>のコンストラクターの1つと一致します。

template <class InputIt>
vector(InputIt first, InputIt last, Allocator const &alloc = Allocator());

実際、char const *をインクリメントして逆参照すると、暗黙的にcharに変換できるintを取得できます。

23
Quentin

"hello""stack"はどちらもconst char *に減衰します。これは InputIterator の概念を満たしています。これにより、それらを一致させることができます std::vectorのコンストラクター#4

std::stringオブジェクトを渡すと、あいまいさが解消されます。

16