2015-08-27 3 views
9

Я ожидаю, что код ниже будет напечатан Test::Test(string,string,bool), однако он печатает Test::Test(string,bool). Почему он вызывает конструктор, который принимает только один строковый параметр, когда два предоставлены? Конечно, строка не может быть преобразована в bool ...? Я попытался добавить явное ключевое слово, но это не поможет. Код также находится в http://ideone.com/n3tep1.C++ неправильный конструктор, который называется

#include <iostream> 
#include <string> 

using namespace std; 

class Test 
{ 
public: 

    Test(const string& str1, bool flag=false) 
    { 
     cout << "Test::Test(string,bool)" << endl; 
    } 

    Test(const string& str1, const string& str2, bool flag=false) 
    { 
     cout << "Test::Test(string,string,bool)" << endl; 
    } 
}; 

int main() 
{ 
    Test* test = new Test("foo", "bar"); 
} 
+7

'«бар»' не является 'станд :: string', это' Const символ * ', а указатель может быть неявно преобразован в' bool', и это преобразование должно иметь приоритет над конструктором 'std :: string (const char *)'. – clcto

+0

Первая версия - лучшее совпадение, попробуйте новый тест («foo», std :: string («bar»)) – Melkon

+6

Что-то вроде примечания, вы обычно не хотите использовать 'new' очень часто в C++-коде , По возможности предпочтительны переменные стека. Просто хедз-ап, так как вы говорите, что вас уже давно нет. – dandan78

ответ

0

Я ожидал бы, что если что-нибудь компилятор будет жаловаться на неоднозначные функции.

Причина, по которой я ожидаю, что вы вызываете неправильный конструктор, заключается в том, что использование строкового литерала приводит к указателю, а указатель может быть неявно преобразован в логическое значение.

В этом случае, по-видимому, компилятор считает, что логическое преобразование лучше соответствует преобразованию в std::string.

+0

У меня есть следующие опции g ++, но нет предупреждений: -pedantic -Wall -Wextra. – user1775138

+1

Логическое преобразование * является лучшим совпадением, чем преобразование в 'std :: string'. – Barry

6

Тип аргумента, который используется для построения Test, составляет char const[4].

char const[4] распадается на char const*, и должен быть преобразован в bool или std::string const&, чтобы сделать вызов функции однозначной.

Указатель может быть преобразован в bool с использованием стандартных правил преобразования.

A char const* может быть преобразован в std::string const& с использованием пользовательского правила преобразования.

Учитывая, что преобразование из char const*, указатель, к bool считается лучше совпадение, чем преобразование из char const* в std::string const&.

Следовательно, вызов переходит к первому конструктору.

2

"bar" имеет типа char const [4], и преобразование от к bool является стандартной последовательностью преобразования, в то время как преобразование в std::string является определенным пользователем преобразования. Первый всегда предпочтительнее последнего.

С N3337, [ко]/1

Стандартных преобразованиями неявных преобразования со встроенным в значении. В пункте 4 перечисляется полный набор таких преобразований. Последовательностьстандартного преобразования представляет собой последовательность стандартных преобразований в следующем порядке:
        - Ноль или один преобразование из следующего набора: именующие к RValue преобразования, массива к указателю преобразование, и преобразование функции в указатель.
        - Ноль или один преобразование из следующего набора: интегральные поощрений, плавающего продвижение точки, интегральные преобразования, преобразование с плавающей запятой с плавающими интегральными преобразованиями, преобразование указателей, указатель на преобразования членов, и логических преобразования.
        - Нулевой или один квалификация.

В вашем примере стандартная последовательность преобразований состоит из преобразования между строками и булевым преобразованием.

[conv.array]/1

Именующее выражение или Rvalue типа «массив N T» или «массив неизвестного граница T» может быть преобразовано в prvalue типа «указатель T ". Результатом является указатель на первый элемент массива.

[conv.bool]/1

prvalue арифметика, незаданного перечисления, указатель, или указателя на типа элемента может быть преобразован в prvalue типа bool. Нулевое значение, значение нулевого указателя или значение указателя нулевого элемента преобразуется в false; любое другое значение преобразуется в true. ...

Таким образом Test("foo", "bar") результаты в вызове конструктора Test(const string&, bool) вместо другого.


Один из способов инициировать вызов в другой конструктор будет использовать string_literals

using namespace std::literals::string_literals; 
Test("foo", "bar"s); // calls Test(const string&, const string&, bool) 
//    ^