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

Что такое тривиальная функция?

[basic.def.odr]/3 ссылается на термин "нетривиальная функция", определение которого я не смог найти в стандарте (N4140).

[basic.def.odr]/3

Переменная x, имя которой отображается как потенциально оцененное выражение ex - odr - используется ex, если не применять преобразование lvalue-to-rvalue (4.1) на x дает постоянное выражение (5.19), которое не вызывает любые нетривиальные функции и, если x - объект, ex - элемент набор потенциальных результатов выражения e, где либо Преобразование lvalue-to-rvalue (4.1) применяется к e или e является выражение сброшенного значения (раздел 5).

4b9b3361

Ответ 1

"нетривиальная функция" является дополнением к "тривиальной специальной функции-члена". Существуют определения того, что тривиальный и нетривиальный конструктор default/copy/move, оператор присваивания копирования/перемещения или деструктор - это признаки, которые относятся только к специальным функциям-членам и определяют, например, их нужно вызывать при определенных обстоятельствах.

Определения для них можно найти в главе § 12.

Конструктор по умолчанию, §12.1/4:

Конструктор по умолчанию является тривиальным, если он не предоставляется пользователем, и если:

  • его класс не имеет виртуальных функций (10.3) и нет виртуальных базовых классов (10.1) и
  • нет нестатического элемента данных его класса, который имеет инициализатор скобок или равный, и
  • все прямые базовые классы его класса имеют тривиальные конструкторы по умолчанию, а
  • для всех нестатических членов данных своего класса, которые относятся к типу класса (или его массиву), каждый из таких классов имеет тривиальное значение по умолчанию конструктор.

В противном случае конструктор по умолчанию является нетривиальным.

Копировать/перемещать конструкторы, §12.8/12:

Конструктор копирования/перемещения для класса X тривиален, если он не является предоставляемый пользователем, его список параметров-параметров эквивалентен parameter-type-list неявного объявления, а если

  • class X не имеет виртуальных функций (10.3) и виртуальных базовых классов (10.1) и
  • class X не имеет нестатических членов данных типа volatile-qualified и
  • конструктор, выбранный для копирования/перемещения каждого подобъекта прямого базового класса, тривиален и
  • для каждого нестатического элемента данных X, который относится к типу класса (или его массиву), конструктор, выбранный для копирования/перемещения этого элемента, тривиальным;

в противном случае конструктор copy/move не является тривиальным.

Операция копирования/перемещения задания, §12.8/26:

Оператор присваивания копирования/перемещения для класса X тривиален, если он не предоставляемый пользователем, его список параметров-параметров эквивалентен parameter-type-list неявного объявления, а если

  • class X не имеет виртуальных функций (10.3) и виртуальных базовых классов (10.1) и
  • class X не имеет нестатических членов данных типа volatile-qualified и
  • оператор присваивания, выбранный для копирования/перемещения каждого прямого базового класса
  • для каждого нестатического элемента данных X, который относится к типу класса (или его массиву), оператор присваивания, выбранный для копирования/перемещения этого член тривиален;

иначе оператор присваивания копирования/перемещения нетривиален.

Деструктор, §12.4/5:

Деструктор тривиален, если он не предоставляется пользователем, и если:

  • деструктор не является виртуальным,
  • все прямые базовые классы его класса имеют тривиальные деструкторы, а
  • для всех нестатических членов данных своего класса, которые относятся к типу класса (или его массиву), каждый такой класс имеет тривиальный деструктор.

В противном случае деструктор является нетривиальным

Ответ 2

Может быть, этот небольшой пример поможет вам понять нетривиальную функцию в контексте [basic.def.odr]/3

struct C { 
        int l; 
        constexpr C(int _l) : l(_l) { } 
        constexpr C(const C&c) : q(c.l* 2) { } 
      }; 

      int main(void) { 
        constexpr C c(42); 
        constexpr int m= c.l; 
        struct K{ 
         int foo() { return c.l; } 
        } l; 
        return l.foo(); 
      } 

Если вы посмотрите на следующую строку в стандартном

Применение преобразования lvalue-to-rvalue (4.1) в x дает константное выражение (5.19), которое не вызывает никаких нетривиальных функций

Здесь c удовлетворяет требованиям к появлению в постоянном выражении, но применение преобразования lvalue-rvalue к вызову a нетривиальная функция.

Почему он вызывает нетривиальную функцию?

Когда преобразование lvalue-rvalue происходит в неоцененном операнде или его подвыражении, значение, содержащееся в ссылочном объекте, не получает доступа. В противном случае, если glvalue имеет тип класса, копия преобразования - инициализирует временный тип T из glvalue, а результат преобразования - это значение для временного

Таким образом, prvalue создается с использованием конструктора копирования класса C, и поскольку конструктор Copy объявлен пользователем, он не является тривиальным и поэтому c не используется ODR здесь

Оператор присваивания копирования/перемещения для класса X является тривиальным, если он не предоставляется пользователям, его список параметров-параметров эквивалентен списку параметров-типа неявного объявления

Надеюсь, этот пример прояснит ваше сомнение.