2014-01-19 4 views
4

Я верю, что приведенный ниже пример на стр. 66 новой книги Bjarne Stroutrup, четвертое издание TCPL, имеет небольшую ошибку, так как у class Vector_container нет конструктора std::initializer_list. Это сообщение об ошибке here.Это предупреждение в clang и gcc кажется неправильным

#include <iostream> 

class Vector{ 
    double* elem; 
    int sz; 
public: 
    Vector(int s):elem{new double[s]}, sz{s} { for(int i = 0; i != sz; ++i) elem[i]= 0; } 
    Vector(std::initializer_list<double> lst): elem{new double[lst.size()]}, sz(lst.size()) { std::copy(lst.begin(), lst.end(), elem); } 
    ~Vector() { delete[] elem; } 
    double& operator[](int i) { return elem[i]; } 
    int size() const { return sz; } 
}; 

class Container{ 
public: 
    virtual double& operator[](int i) = 0; 
    virtual int size() const = 0; 
    virtual ~Container() {} 
}; 

class Vector_container:public Container{ 
    Vector v; 
public: 
    Vector_container(int s): v{s}{} 
    ~Vector_container() {} 
    double& operator[](int i) { return v[i]; } 
    int size() const {return v.size(); } 
}; 

void use(Container& c) 
{ 
    const int sz = c.size(); 
    for(int i = 0; i != sz; i++) std::cout << c[i] << '\n'; 
} 

int main() 
{ 
    Vector_container vc{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; 
    use(vc); 
} 

Но предупреждение испускается для выражения v{s} в списке члена-инициализаторе для Vector_container(int) конструктора удивил меня, так как она говорит: warning: narrowing conversion of 's' from 'int' to 'double' inside { }, который не кажется правильным, так как нет Сужения в этом случае ,

Также, если вы изменили выражение Vector_container vc{10, ..., 1}; в main() на Vector_container vc{10};, сообщение об ошибке исчезнет, ​​как и ожидалось, но предупреждение продолжает демонстрироваться. Тем не менее конструктор std::initializer-list для класса Vector выбран компилятором, и я полагаю, что это правильно, согласно стандарту 13.3.1.7/1.

Таким образом, интересно , если есть какой-нибудь способ навязать вызове формы Vector(int) конструктора, вместо инициализатора-лист CTOR в Vector классе, в последнем примере с Vector_container vc{10};.

+0

Внутри 'Vector_container (Int S)', ' s' не является постоянным выражением, поэтому происходит сужение преобразования от 'int' до' double'. clang ++ 3.5 говорит, что это * ошибка *, а не просто предупреждение. – dyp

+0

* "Таким образом, мне интересно, есть ли способ навязать вызов конструктора' Vector (int) '. * Не использовать инициализацию списка в' Vector_container (int s) '? -> 'Vector_container (int s): v (s) {}' – dyp

+0

@dyp 'Не использовать инициализацию списка в Vector_container (int s)?' Но что, если вы хотите сохранить этот конструктор в классе? –

ответ

4

Вы правильно о разрешении перегрузки: Внутри

Vector_container(int s): v{s}{} 

инициализации v{s} выбирает следующий конструктор:

Vector(std::initializer_list<double> lst) 

согласно [over.match.list]/1.

Когда std::initializer_list<double> создается из {s}, где s имеет тип int, существует сужающее преобразование из int в double (n3485) [dcl.init.list]/7

Конверсия сужение неявное преобразование

  • [...]
  • от целого типа или типа перечисления незаданного к типу с плавающей точкой, за исключением Whe повторно источника является постоянным выражением и фактическое значение после преобразования будет вписываться в целевой тип и производить первоначальное значение при преобразовании обратно в исходный тип, или
  • [...]

Обратите внимание, что s здесь больше не является постоянным выражением (являющимся параметром). Сужающие преобразования могут не отображаться в строительстве std::initializer_list объекта, [dcl.init.list]/5

Если сужающее преобразование требуется для инициализации любого из элементов, программа плохо сформирована.

Так что предупреждение должно быть ошибкой (или это расширение).


Таким образом, я задаюсь вопросом, есть ли способ, чтобы наложить вызове формы Vector(int) конструктора, вместо инициализатора-лист CTOR в Vector классе.

Я не уверен, если я правильно понял (см комментарии к OP), но не используя список иниц здесь решает проблему:

Vector_container(int s): v(s) {} // initializer-list ctor not viable 
+0

' Vector_container (int s): v (s) {} 'Именно это я и искал. Таким образом вы принудительно вызываете конструктор Vector (int), который вызывается. G ood ответ. Tks. –

+0

Еще одна ошибка «единой инициализации». Возможно, если бы он не включал инициализацию 'std :: initializer_list', это было бы менее сложно и менее неожиданно ... – dyp

+0

' Когда std :: initializer_list создан из {s}, где s имеет тип int, существует сужение преобразования от int до double (n3485) [dcl.init.list]/7' Но какова реальная проблема с этим так называемым «сужающимся» преобразованием? –

Смежные вопросы