Я пытаюсь перенести свой проект из Visual Studio 2010 в Visual Studio 2012. В моем коде есть некоторая обработка файлов, которая выглядит следующим образом:
auto fileDeleter = [](FILE* f) { fclose(f); };
unique_ptr<FILE, decltype(fileDeleter)> fMinute(
fopen(minuteLogName.c_str(), "w"), fileDeleter);unique_ptr<FILE, decltype(fileDeleter)> fIndividual(
fopen(individualLogName.c_str(), "w"), fileDeleter);
if (!fMinute || !fIndividual) {
throw Exceptions::IOException("One of the log files failed to open",
__FUNCTION__);
}
Это построено без проблем в 2010, но в 2012 это терпит неудачу на условии:
ошибка C2678: двоичный файл «!» : не найден оператор, который принимает левый операнд типа> ‘std :: unique_ptr<_Ty, _Dx> ‘(или нет приемлемого преобразования)
…
может быть «встроенным оператором C ++! (bool)»
Стандарт C ++ 11 указывает, что unique_ptr имеет оператор bool чтобы позволить вам сделать быстрые проверки, как у меня выше. Еще более странно, что определение VS2012 unique_ptr имеет этот самый оператор:
_OPERATOR_BOOL() const _NOEXCEPT
{ // test for non-null pointer
return (this->_Myptr != pointer() ? _CONVERTIBLE_TO_TRUE : 0);
}
Но я получаю эту ошибку при компиляции. Зачем?
Да, я мог бы просто использовать ofstream
вместо этого, но это не главное.
Чтобы опираться на то, что сказал BigBoss, C ++ 11 требует, чтобы std::unique_ptr
использование explicit operator bool() noexcept
, который решает все неявное преобразование в проблему bool. Кроме … VC2012 нет служба поддержки explicit
Операторов пока нет. Поэтому они должны использовать идиома «безопасный бул».
Хотя идиома «безопасный бул» хороша, у нее могут быть недостатки (вот почему explicit operator bool()
существует), в зависимости от того, как вы реализуете идиому. И вы, очевидно, столкнулись с одним из них в VC2012. Переконфигурирование вашего теста, с !(fMinute && fIndividual)
, должен решить это.
Но в любом случае, это ошибка Visual Studio. Поскольку поведение изменилось, вы должны подать отчет об ошибке, даже если вам удастся найти способ обойти это.
Ты можешь использовать if (!(fMinute && fIndividual) )
вместо if (!fMinute || !fIndividual)
, C ++ говорят, что они конвертируются в bool, но operator bool
обычно создают проблемы, например, у вас может быть функция, которая принимает int
, если у вашего класса есть operator bool
тогда он конвертируется в int, и вы можете передать его этой функции, но, например, в нашем случае unique_ptr
никогда не предназначен для использования в качестве int
так много разработчиков никогда не используют operator bool
напрямую, но вместо этого напишите оператор, который можно использовать в качестве условного выражения в условных выражениях, но на самом деле он не является логическим выражением!
struct bool_convertible {
typedef void (*convertible_to_bool)();
static void convertible_to_true();
operator convertible_to_bool () const {
return test() ? &convertible_to_true : nullptr;
}
};
Используя эту технику, я могу иметь bool_convertible c; if( c ) {...}
но я не могу иметь
void test_int( int );
bool_convertible c;
test_int( c );
В недавнем стандарте C ++ 11 std :: unique_ptr не имеет operator!
определено, только явный оператор преобразования
explicit operator bool() const;
Тем не менее, встроенный унарный логический оператор отрицания, !
контекстуально преобразует свой аргумент в bool согласно 5.3.1 / 9:
Операнд оператора логического отрицания
!
контекстно преобразуется вbool
(Пункт 4); его значение равно true, если преобразованный операнд равен false, в противном случае — false
Контекстное преобразование в bool будет использовать явный оператор преобразования, если он доступен. Итак, ваш код должен работать по правилам C ++ 11. Возможно, вам следует подать отчет об ошибке в Microsoft. Поддерживают ли они явные операторы преобразования или нет, не имеет значения.
В качестве обходного пути попробуйте это:
if (!fMinute.get() || !fIndividual.get()) {
....