Как устранить неоднозначность между конструкторами, принимающими std :: string и std :: vector - PullRequest
0 голосов
/ 13 декабря 2018

Я хочу создать класс «Tag», имя которого можно указать либо в виде имени, разделенного точкой, например "this.is.my.name", либо в виде вектора строк, например {"this","is","my","name"}.

Когда я пытаюсь это сделать, мне иногда говорят компилятор, что мои вызовы неоднозначны.Я хочу знать, (1) почему это вообще неоднозначно, и (2) почему это иногда только неоднозначно.

Вот мой пример кода, который вы также можете просмотреть и скомпилировать здесь, в Coliru

#include <string>
#include <vector>
#include <iostream>

class Tag
{
public:
    explicit Tag(std::string name);
    explicit Tag(std::vector<std::string> name);

};

Tag::Tag(std::string name)
{
    //here 'name' will be a dotted collection of strings, like "a.b.c"
}

Tag::Tag(std::vector<std::string> name)
{
    //here 'name' will be a vector of strings, like {"a","b","c"}
}


int main(int argc, char**argv)
{
    Tag imaTag{{"dotted","string","again"}};
    Tag imaTagToo{"dotted.string"};

    //everything is fine without this line:
    Tag imaTagAlso{{"dotted","string"}};
    std::cout << "I made two tags" << std::endl;

}

С указанной строкой я получаю следующую ошибку:

g++ -std=c++11 -O2 -Wall -pthread main.cpp && ./a.out
main.cpp: In function 'int main(int, char**)':
main.cpp:28:39: error: call of overloaded 'Tag(<brace-enclosed initializer list>)' is ambiguous
     Tag imaTagAlso{{"dotted","string"}};
                                   ^
main.cpp:18:1: note: candidate:     'Tag::Tag(std::vector<std::__cxx11::basic_string<char> >)'
 Tag::Tag(std::vector<std::string> name)
 ^~~
main.cpp:13:1: note: candidate: 'Tag::Tag(std::__cxx11::string)'
 Tag::Tag(std::string name)
 ^~~

1 Ответ

0 голосов
/ 13 декабря 2018

Tag imaTagAlso{{"dotted","string"}}; говорит, что создайте Tag, назовите его imaTagAlso и инициализируйте его с {"dotted","string"}.Проблема с этим std::string может быть создана парой итераторов, и поскольку строковые литералы могут уменьшаться до const char*, они квалифицируются как итераторы.Таким образом, вы можете либо вызвать строковый конструктор, используя «итераторы», либо вы можете вызвать векторный конструктор, используя его std::initializer_list конструктор.Чтобы обойти это, вы можете использовать

Tag imaTagAlso{{{"dotted"},{"string"}}};

, который говорит, что создайте Tag, назовите его imaTagAlso и инициализируйте его с помощью {{"dotted"},{"string"}}, и теперь {"dotted"} и {"string"} станут элементами std::initializer_list для векторного конструктора.

Вы также можете (начиная с c ++ 14) использовать std::string пользовательский литеральный оператор (""s) , как

Tag imaTagAlso{{"dotted"s,"string"s}};

, который делает каждыйэлемент braced-init-list std::string и будет выбран векторный конструктор.

...