Поведение If constexpr в C

#c #if-statement

Вопрос:

Даже имея много вопросов по этой теме, у меня возникает все больше и больше проблем. Я думаю, что проблема в понимании значения определенных слов. Все приведенные ниже цитаты взяты из Cppreference

  1. Что означает «отброшено» в приведенном ниже тексте? Я понимаю «отброшенный» как что-то, что никогда не компилировалось/не трогалось, что-то, что, чем бы это ни было (например, случайные символы, которые были бы ошибками), не будет вмешиваться в остальную часть программы.

В инструкции constexpr if значение условия должно быть контекстуально преобразованным постоянным выражением типа bool (до C 23), выражением, контекстуально преобразованным в bool, где преобразование является постоянным выражением (начиная с C 23). Если значение true, то оператор-false отбрасывается (если присутствует), в противном случае оператор-true отбрасывается.

  1. Что значит «инстанцированный»?

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

  1. Что значит «проверено»? Я понимаю, что «проверено» означает, что код был полностью скомпилирован и проверен на любую возможную ошибку в то время.

За пределами шаблона отброшенный оператор полностью проверяется. if constexpr не является заменой директивы #if предварительной обработки:

Комментарии:

1. Отброшено: пропущено, проигнорировано, как будто его там не было.

2. Экземпляр: используется в контексте шаблонов. Означает, что шаблон «воплощен» (фактически определен ) с использованием заданных конкретных аргументов шаблона.

3. @YvesDaoust: Сложнее, чем это, как объяснено в пунктах 2 и 3. «отброшено» действительно вводит в заблуждение ИМО.

4. Проверено: в любом случае это должно быть действительное утверждение. (Даже если его можно отбросить.)

5. Фактически, пункт 1 различает два блока и называет оператор/ветвь, которая не удовлетворяет условию, чтобы впоследствии придать ей некоторые «свойства».

Ответ №1:

Рассмотрим этот пример:

 #include <iostream>
#include <string>

template <typename T>
void foo() {
    T t;
    if constexpr (std::is_same_v<T,std::string>){
        std::cout << t.find("asd");
    } else {
        t = 0;
        std::cout << t;
    }
}

int main () {
    foo<int>();                     // (2)
}
 

Когда T тип, у которого нет find метода, std::cout << t.find("asd") является ошибкой. Тем не менее, шаблон в порядке.

  1. Что значит «инстанцированный»?

Экземпляр шаблона создан в (2) . foo это всего лишь шаблон, создание экземпляра которого приводит к функции foo<int> , которую вы можете вызвать.

  1. Что означает «отброшено» в приведенном ниже тексте?

Истинная ветвь отбрасывается при foo<int> создании экземпляра (потому что условие есть false ). Следовательно, даже если int у него нет find метода, код компилируется без ошибок.

Теперь рассмотрим этот аналогичный, но совсем другой пример:

 #include <iostream>

int main () {
    int x = 0;
    if constexpr (true) {
        std::cout << x;
    } else {
        x.find("asd");
    }
}
 
  1. Что значит «проверено»?

Текст немного надуман, в нем говорится, что в приведенном выше примере false ветвь отбрасывается, но тем не менее она проверяется, потому что находится вне шаблона. Это просто английский термин: «проверено» означает, что компилятор проверяет правильность кода. int не имеет метода find , следовательно, вышеизложенное приводит к ошибке:

 <source>:8:15: error: request for member 'find' in 'x', which is of non-class type 'int'
    8 |             x.find("asd");
      |               ^~~~
 

Даже если это утверждение никогда не выполняется, оно должно быть допустимым кодом.

Комментарии:

1. что делать, если изменение std::cout << t.find("asd"); в вашем первом коде, на whatever contains errors ?.

2. @Roman тогда это то же самое. std::cout < Вы можете заменить его другой ошибкой и все равно foo<int>() выполнить компиляцию. Только когда T == std::строка кода в ветви true не отбрасывается и не проверяется