Составляет ли constexpr встроенный?
Рассмотрим следующую встроенную функцию:
// Inline specifier version
#include<iostream>
#include<cstdlib>
inline int f(const int x);
inline int f(const int x)
{
return 2*x;
}
int main(int argc, char* argv[])
{
return f(std::atoi(argv[1]));
}
и эквивалентной версии constexpr:
// Constexpr specifier version
#include<iostream>
#include<cstdlib>
constexpr int f(const int x);
constexpr int f(const int x)
{
return 2*x;
}
int main(int argc, char* argv[])
{
return f(std::atoi(argv[1]));
}
Мой вопрос: спецификатор constexpr
подразумевает спецификатор inline
в том смысле, что если непостоянный аргумент передается функции constexpr
, компилятор будет пытаться inline
использовать функцию как бы спецификатор inline
был помещен в его объявление?
Гарантирует ли стандарт С++ 11?
Ответы
Ответ 1
Да ([dcl.constexpr], §7.1.5/2 в стандарте С++ 11): "Функции constexpr и конструкторы constexpr неявно встроены (7.1.2)".
Обратите внимание, однако, что спецификатор inline
действительно очень мало (если вообще имеет) влияет на то, может ли компилятор расширять встроенную функцию или нет. Однако это влияет на одно правило определения, и с этой точки зрения компилятор должен следовать тем же правилам для функции constexpr
, что и функция inline
.
Я также должен добавить, что независимо от того, constexpr
подразумевает inline
, правила для функций constexpr
в С++ 11 требовали, чтобы они были достаточно простыми, чтобы они часто были хорошими кандидатами для встроенного расширения (главным исключением являются те, которые рекурсивный). Однако с тех пор правила стали все более и более свободными, поэтому constexpr
можно применять к существенно более крупным и более сложным функциям.
Ответ 2
constexpr
не подразумевает inline
для нестатических переменных (C++ 17 встроенных переменных)
Хотя constexpr
подразумевает inline
для функций, он не имеет такого эффекта для нестатических переменных, учитывая C++ 17 встроенных переменных.
Например, если вы возьмете минимальный пример, который я опубликовал по адресу: Как работают встроенные переменные? и удалите inline
, оставив только constexpr
, тогда переменная получит несколько адресов, что является главным избегайте встроенных переменных.
constexpr
статические переменные неявно статичны.
Минимальный пример того, что constexpr
подразумевает inline
для функций
Как упомянуто на: fooobar.com/info/106435/... основной эффект inline
состоит не в том, чтобы встроить, а в том, чтобы позволить несколько определений функции, стандартная цитата на: Как заголовочный файл C++ может включать реализацию?
Мы можем наблюдать это, играя на следующем примере:
main.cpp
#include <cassert>
#include "notmain.hpp"
int main() {
assert(shared_func() == notmain_func());
}
notmain.hpp
#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP
inline int shared_func() { return 42; }
int notmain_func();
#endif
notmain.cpp
#include "notmain.hpp"
int notmain_func() {
return shared_func();
}
Скомпилируйте и запустите:
g++ -c -ggdb3 -O0 -Wall -Wextra -std=c++11 -pedantic-errors -o 'notmain.o' 'notmain.cpp'
g++ -c -ggdb3 -O0 -Wall -Wextra -std=c++11 -pedantic-errors -o 'main.o' 'main.cpp'
g++ -ggdb3 -O0 -Wall -Wextra -std=c++11 -pedantic-errors -o 'main.out' notmain.o main.o
./main.out
Если мы удалим inline
из shared_func
, ссылка потерпит неудачу с:
multiple definition of 'shared_func()'
потому что заголовок включается в несколько файлов .cpp
.
Но если мы заменим inline
на constexpr
, то он снова будет работать, потому что constexpr
также подразумевает inline
.
GCC реализует это, помечая символы как слабые в объектных файлах ELF: Как заголовочный файл C++ может включать реализацию?
Протестировано в GCC 8.3.0.