2

Рассмотрят следующий код, который иллюстрирует некоторые преобразования сужения:Force предупреждение сужая преобразование

template <class T> 
class wrapper 
{ 
    template <class> friend class wrapper; 
    public: 
     constexpr wrapper(T value) 
     : _data(value) 
     {} 
     template <class U> 
     constexpr wrapper(wrapper<U> other) 
     : _data(other._data) 
     {} 
     wrapper& operator=(T value) 
     {_data = value; return *this;} 
     template <class U> 
     wrapper& operator=(wrapper<U> other) 
     {_data = other._data; return *this;} 
    private: 
     T _data; 
}; 

int main(int argc, char* argv[]) 
{ 
    wrapper<unsigned char> wrapper1 = 5U; 
    wrapper<unsigned char> wrapper2{5U}; 
    wrapper<unsigned char> wrapper3(5U); 
    wrapper<unsigned int> wrapper4 = 5U; 
    wrapper<unsigned int> wrapper5{5U}; 
    wrapper<unsigned int> wrapper6(5U); 
    wrapper<unsigned char> wrapper7 = wrapper4; // Narrowing 
    wrapper<unsigned char> wrapper8{wrapper5}; // Narrowing 
    wrapper<unsigned char> wrapper9(wrapper6); // Narrowing 
    wrapper7 = wrapper4; // Narrowing 
    wrapper8 = wrapper5; // Narrowing 
    wrapper9 = wrapper6; // Narrowing 
    return 0; 
} 

Как изменить тело из wrapper членов, так что это вызывает предупреждение компилятора для сокращения преобразования? Моя цель - информировать пользователя о том, что что-то не так с их кодом.

+4

Где сужается? Вы копируете инициализацию из одного и того же типа в 7, 8 и 9. – NathanOliver

+0

Интересно, что есть '-Wnarrowing', но он ничего не делает. В этом случае сужение ошибок становится намного проще. – krzaq

+0

@NathanOliver Спасибо, исправлена ​​проблема. – Vincent

ответ

5

Вы можете вызвать предупреждение сужающего преобразования с однородным синтаксисом инициализации:

class wrapper 
{ 
    template <class> friend class wrapper; 
    public: 
     constexpr wrapper(T value) 
     : _data{value} 
     {} 
     template <class U> 
     constexpr wrapper(wrapper<U> other) 
     : _data{other._data} // note the curly brackets here 
     {} 
     wrapper& operator=(T value) 
     {_data = value; return *this;} 
     template <class U> 
     wrapper& operator=(wrapper<U> other) 
     {_data = {other._data}; return *this;} // and here 
    private: 
     T _data; 
}; 

с

wrapper<unsigned int> wrapper1 = 5U; 
wrapper<unsigned char> wrapper2 = wrapper1; // Narrowing 
wrapper<unsigned char> wrapper3(wrapper1); // Narrowing 
wrapper<unsigned char> wrapper4{wrapper1}; // Narrowing 
wrapper2 = wrapper1; // Narrowing 

любые из четырех последних строк will produce a narrowing conversion warning in g++, and compilation errors from the narrowing conversions in clang.

0

Я рекомендовал бы по-другому. Вам не нужно гадать с кодом. Когда вы компилируете с помощью g ++, добавьте флаг -Wconversion.

+0

Часть проблемы - шаблон OP частично замыкает предупреждение. – user4581301

3

Чтобы остановить компиляцию в сужению вызова вы можете использовать SFINAE на

template <class U> 
constexpr wrapper(wrapper<U> other) 
: _data(other._data) 
{} 

И изменить его на

template <class U, typename std::enable_if<sizeof(T) >= sizeof(U)>::type* = nullptr> 
constexpr wrapper(wrapper<U> other) 
: _data(other._data) 
{} 

Live Example

Это остановит компиляцию, если размер основной тип, который вы копируете, больше, чем базовый тип объекта, который вы инициализируете.

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