Как работают встроенные переменные?
на встрече стандартов ISO C++ 2016 года в Оулу было выдвинуто предложение под названием Встроенные Переменные был проголосован в C++17 комитетом по стандартам.
в терминах непрофессионала, что такое встроенные переменные, как они работают и для чего они полезны? Как следует объявлять, определять и использовать встроенные переменные?
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.
(есть еще варианты использования для синглтона Мейера, например, если вы явно хотите иметь ленивую инициализацию.)