Подтвердить что ты не робот

Ожидаются ли правила оценки короткого замыкания во время компиляции?

Программа A создает ошибку компиляции (как ожидалось), так как isFinite вызывается с нецелым типом.

Программа A

#include <iostream>

class Foo {};

template<typename T>
bool isFinite(const T& t)
{
    static_assert(std::is_integral<T>::value, "Called isFinite with a non-integral type");
    return false;
}

int main()
{
    Foo f;
    std::cout << "Foo is finite? " << ((isFinite(f)) ? "yes" : "no") << "\n";

    return 0;
}

Однако небольшая модификация (см. Программа B) позволяет программе скомпилировать (Visual Studio 2013) и произвести следующий вывод.

Программа B Visual Studio 2013 Ouput

Foo is finite? yes

Программа B

#include <iostream>

class Foo {};

template<typename T>
bool isFinite(const T& t)
{
    static_assert(std::is_integral<T>::value, "Called isFinite with a non-integral type");
    return false;
}

int main()
{
    Foo f;
    std::cout << "Foo is finite? " << ((true || isFinite(f)) ? "yes" : "no") << "\n";

    return 0;
}

Похоже, что Программа B коротко замыкается на логическую операцию ИЛИ и не пытается скомпилировать остальную часть выражения. Однако, это приложение не компилируется с помощью g++ 4.8.3 (g++ -std=c++11 -o main main.cpp). Я получаю следующий вывод.

main.cpp: In instantiation of 'bool isFinite(const T&) [with T = Foo]':
main.cpp:15:56:   required from here
main.cpp:8:2: error: static assertion failed: Called isFinite with a non-integral type
  static_assert(std::is_integral<T>::value, "Called isFinite with a non-integral type");
  ^

Моя интуиция заставляет меня думать, что сбой компиляции - это правильное поведение , но любопытно, что Visual Studio 2013 успешно компилируется. Моя интуиция основана на том факте, что ожидается, что следующий код не может быть скомпилирован.

#include <iostream>

struct Foo
{
    void doOperation1() {}
    void doOperation2() {}
};

struct Bar
{
    void doOperationA() {}
    void doOperation2() {}
};

template<typename T>
void performOperation(T& t, bool value)
{
    if (value)
    {
        t.doOperation1();
    }
    else
    {
        t.doOperation2();
    }
}

int main()
{
    Foo f;
    performOperation(f, true);
    performOperation(f, false);

    Bar b;
    performOperation(b, false); // Fails to compile (as expected)

    return 0;
}

Повторный вопрос

Предполагаются ли логические операторы придерживаться правил оценки коротких замыканий во время компиляции (т.е. каково ожидаемое поведение компиляции Программы B)?

4b9b3361

Ответ 1

Короткое замыкание не должно компилироваться true || (whatever_ill_formed). isFinite<Foo> создается как часть выражения, и во время создания экземпляра он должен быть скомпилирован, и во время компиляции он должен статически утверждать. После этого компилятор никогда не сможет оценить isFinite<Foo>(f) из-за короткого замыкания, но статическое утверждение не должно произойти во время него.

Непонятно, почему Visual Studio 2013 компилирует программу B. Стандарт только позволяет обходить проверку синтаксиса шаблонов, когда шаблон никогда не создается. Даже тогда код все еще плохо сформирован, только диагностика не требуется. За недостатком, пожалуй, одна и та же внутренняя проблема в Visual С++, которая не позволяет Microsoft реализовать constexpr.

Изменить. Я добавляю тексты текстов для юридических лиц из стандартного запроса @zneak

3.2/3

Функция, имя которой отображается как потенциально оцененное выражение, odr - используется, если это уникальный результат поиска или выбранный член набор перегруженных функций (3.4, 13.3, 13.4), если только он не является чистым виртуальная функция и ее имя явно не квалифицированы. [Примечание: это охватывает вызовы названных функций (5.2.2), перегрузку оператора (пункт 13), определяемые пользователем преобразования (12.3.2), функция распределения для размещение нового (5.3.4), а также инициализацию не по умолчанию (8.5). конструктор, выбранный для копирования или перемещения объекта типа класса, является odr-used, даже если вызов действительно устранен реализацией (12,8). -end note]

5.13/1

|| группы операторов слева направо. Операнды оба контекстно преобразованный в bool (раздел 4). Он возвращает true, если его операндов истинно, а false в противном случае. В отличие от |, || гарантии оценка слева направо; кроме того, второй операнд не оценивается, если первый операнд имеет значение true.

7.1/4

В объявлении static_assert константное выражение должно быть постоянное выражение (5.19), которое можно контекстно преобразовать в bool (Пункт 4). Если значение выражения при его преобразовании истинно, выражение не имеет никакого эффекта. В противном случае программа плохо сформирована, и в результате диагностического сообщения (1.4) должен быть включен текст строковый литерал, за исключением того, что символы не находятся в базовом источнике набор символов (2.3) не требуется появляться в диагностике сообщение.

14.7.1/3

Если спецификация шаблона функции явно не указана экземпляр или явно специализированный, шаблон функции специализация неявно создается, когда специализация ссылается в контексте, который требует определения функции.