Составляет ли 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.