Как работают встроенные переменные?


на встрече стандартов ISO C++ 2016 года в Оулу было выдвинуто предложение под названием Встроенные Переменные был проголосован в C++17 комитетом по стандартам.

в терминах непрофессионала, что такое встроенные переменные, как они работают и для чего они полезны? Как следует объявлять, определять и использовать встроенные переменные?

2 76

2 ответа:

первое предложение:

" The inline спецификатор может применяться как к переменным, так и к функциям.

1guaranteed эффект inline применительно к функции, это позволяет определить функцию идентично, с внешней связью, в нескольких единицах перевода. На практике это означает определение функции в заголовке, которая может быть включена в несколько единиц перевода. Этот предложение расширяет эту возможность на переменные.

Итак, в практическом плане (теперь принятое) предложение позволяет использовать inline ключевое слово для определения внешней связи const переменной пространства имен или каких-либо static член класса данных, в файле заголовка, так что несколько определений, которые приводят, когда этот заголовок включен в несколько единиц перевода в порядке с компоновщиком-он просто выбирает один из них.

до и включая C++14 внутренний механизм для этого был там, чтобы поддержать static переменные в шаблонах классов, но не было удобного способа использовать этот механизм. Приходилось прибегать к таким трюкам, как

template< class Dummy >
struct Kath_
{
    static std::string const hi;
};

template< class Dummy >
std::string const Kath_<Dummy>::hi = "Zzzzz...";

using Kath = Kath_<void>;    // Allows you to write `Kath::hi`.

С C++17 и далее я считаю, что можно писать просто

struct Kath
{
    static std::string const hi;
};

inline std::string const Kath::hi = "Zzzzz...";    // Simpler!

... в заголовочном файле.

предложение включает в себя формулировку

" встроенный статический элемент данных может быть определен в определении класса и может указать бандаж или равно инициализатор. Если элемент объявлен с помощью constexpr спецификатор, он может быть повторно объявлен в области пространства имен без инициализатора (это использование устарело; см. D. X). Объявления других статических элементов данных не должны указывать инициализатор скобки или равенства

... что позволяет еще больше упростить вышесказанное до просто

struct Kath
{
    static inline std::string const hi = "Zzzzz...";    // Simplest!
};

... как отмечает T. C in комментарий для этого ответ.

и ​constexpr спецификатор означает inline для статических элементов данных, а также функции.


Примечания:
1 для функции inline также имеет эффект намека на оптимизацию, что компилятор должен предпочесть заменить вызовы этой функции прямой заменой машинного кода функции. Этот намек можно проигнорировать.

встроенные переменные очень похожи на встроенные функции. Он сигнализирует компоновщику, что должен существовать только один экземпляр переменной, даже если переменная видна в нескольких единицах компиляции. Компоновщик должен убедиться, что больше не создаются копии.

встроенные переменные могут использоваться для определения глобалов только в библиотеках заголовков. До C++17 они должны были использовать обходные пути (встроенные функции или шаблонные хаки).

например, один обходной путь заключается в использовании Мейера синглтон со встроенной функцией:

inline T& instance()
{
  static T global;
  return global;
}

есть некоторые недостатки, с таким подходом, в основном с точки зрения производительности. Этих накладных расходов можно было бы избежать с помощью шаблонных решений, но их легко ошибиться.

С помощью встроенных переменных вы можете напрямую объявить его (без получения ошибки компоновщика с несколькими определениями):

inline T global;

помимо библиотек только заголовков, есть и другие случаи, когда встроенные переменные могут помочь. НИР Фридман освещает эту тему в своем поговорите на CppCon:что разработчики C++ должны знать о глобалах (и компоновщике). Часть о встроенных переменных и обходных путях начинается в 18m9s.

(есть еще варианты использования для синглтона Мейера, например, если вы явно хотите иметь ленивую инициализацию.)