Вы видите комбинацию нескольких эффектов.
- Вызов в вашем
main()
совершенно законен, потому что экземпляр шаблона make_unique
соответствует подписанному типу данных, который вы его передаете.
- Реализация
make_unique
не генерирует предупреждения, потому что предупреждения обычно отключены внутри системных заголовков.
- Visual Studio, похоже, не может обнаружить потенциальную (но не определенную) проблему преобразования знака внутри
make_unique
.
Подробнее:
1. Создание экземпляра шаблона действительно законно.
Типичная реализация std::make_unique
выглядит так (сравните cppreference):
template <typename T, typename... Args>
inline std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
В вашем случае при вызове std::make_unique<MyClass>(-1)
шаблон создается для подписанного целого числа. Следовательно, вы не получаете предупреждения в своем коде, потому что преобразование без знака / знака не происходит.
2. Системные заголовки обычно отключают предупреждения.
Однако вы могли с полным правом ожидать предупреждения от make_unique
реализации. В конце концов, когда new T(...)
вызывается с вашим параметром со знаком, преобразование со знаком / без знака все равно происходит. В качестве примера возьмем следующую программу:
#include <memory>
class MyClass
{
public:
MyClass(unsigned) { }
};
template <typename T, typename... Args>
inline std::unique_ptr<T> custom_make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
int main()
{
auto uniqueP = custom_make_unique<MyClass>(-1);
(void) uniqueP;
return 0;
}
Когда я компилирую это с помощью GCC с -Wsign-conversion
, я получаю предупреждение
test.cpp: при создании экземпляра 'std :: unique_ptr ‹_Tp> custom_make_unique (Args && ...) [с T = MyClass; Args = {int}] ':
test.cpp: 17: 48: требуется отсюда
test.cpp: 12: 63: предупреждение: преобразование в' unsigned int 'из' int 'может изменить знак результат [-Wsign-conversion]
return std :: unique_ptr (new T (std :: forward (args) ...));
Возникает вопрос, почему вы не получаете это предупреждение для реализации std::make_unique()
? По сути, ответ заключается в том, что компилятор заглушает эти предупреждения для своих системных заголовков. Например, версия заголовка <memory>
GCC содержит прагму
#pragma GCC system_header
Как только эта прагма присутствует в файле заголовка, компилятор больше не сообщает предупреждения обо всем, что находится внутри этого заголовка. Из документации GCC:
Заголовочные файлы, объявляющие интерфейсы к операционной системе и библиотекам времени выполнения, часто не могут быть написаны на строго соответствующем языке C. Таким образом, GCC предоставляет коду, находящемуся в системных заголовках, особую обработку. Все предупреждения, кроме тех, которые генерируются «#warning
» (см. «Диагностика»), подавляются, пока GCC обрабатывает системный заголовок.
См. Также эту публикацию SO для получения дополнительных сведений. Предположительно, аналогичный подход используется компилятором Visual Studio (и, как вы написали в своем комментарии, заголовок временно снижает уровень предупреждения).
3. Похоже, вы столкнулись с ограничением VisualStudio.
В случае с VisualStudio работает еще кое-что. Обратите внимание, как в предупреждении GCC выше говорится, что может быть проблема преобразования знака (в зависимости от того, какие значения пользователи позже будут вводить в custom_make_unique
). Похоже, что VisualStudio может предупреждать только в случае определенной проблемы преобразования знака. См. Следующую программу:
#include <iostream>
void f(unsigned) { }
template <typename T>
void g(T val) { f(val); } // GCC issues a warning, VS does NOT
int main()
{
f(-1); // GCC and VS issue a warning
g(-1); // no conversion warning here (g<int> instantiated)
}
Попробуйте в Интернете.
person
mindriot
schedule
21.02.2018