Проблемы с C ++ 11 при переходе с Visual Studio 2010 на 2012

Я пытаюсь перенести свой проект из 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 вместо этого, но это не главное.

7

Решение

Чтобы опираться на то, что сказал BigBoss, C ++ 11 требует, чтобы std::unique_ptr использование explicit operator bool() noexcept, который решает все неявное преобразование в проблему bool. Кроме … VC2012 нет служба поддержки explicit Операторов пока нет. Поэтому они должны использовать идиома «безопасный бул».

Хотя идиома «безопасный бул» хороша, у нее могут быть недостатки (вот почему explicit operator bool() существует), в зависимости от того, как вы реализуете идиому. И вы, очевидно, столкнулись с одним из них в VC2012. Переконфигурирование вашего теста, с !(fMinute && fIndividual), должен решить это.

Но в любом случае, это ошибка Visual Studio. Поскольку поведение изменилось, вы должны подать отчет об ошибке, даже если вам удастся найти способ обойти это.

6

Другие решения

Ты можешь использовать 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 );
1

В недавнем стандарте 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()) {
....
1
По вопросам рекламы [email protected]