Чи має на увазі constexpr вбудований?


105

Розглянемо наступну вбудовану функцію:

// 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специфікатор був введений у свою декларацію?

Чи гарантує це стандарт C ++ 11?


5
"[Чи буде] компілятор спробувати вбудувати функцію" - це не те, що inlineробить специфікатор. (А може, я неправильно зрозумів вашу фразу.)
Люк Дантон,

5
Специфікатор inlineбільше не має нічого спільного з вбудовою
K-бал

2
Питання стоїть на помилковому припущенні, яке inlineбезпосередньо пов’язане з вбудовою. Отже, ні, constexprспецифікатор не має на увазі inlineспецифікатора в цьому сенсі, оскільки цього сенсу не існує.
Крістіан Рау

Відповіді:


139

Так ([dcl.constexpr], § 7.1.5 / 2 стандарту C ++ 11): "функції constexpr та конструктори constexpr неявно вбудовані (7.1.2)."

Однак зауважте, що inlineспецифікатор дійсно має дуже малий (якщо такий є) вплив на те, чи може компілятор розширити функцію вбудованою чи ні. Однак це впливає на одне правило визначення, і з цього погляду від компілятора потрібно дотримуватися тих самих правил для constexprфункції, що й inlineфункція.

Я також хочу додати, що незалежно від того, constexprщо передбачає inline, правила для constexprфункцій в C ++ 11 вимагають, щоб вони були досить простими, щоб вони часто були хорошими кандидатами для вбудованого розширення (головним винятком є ​​рекурсивні). Однак відтоді правила constexprстають прогресивнішими, тому їх можна застосовувати до значно більших, складніших функцій.


Зважаючи на те, що ідея полягає в тому, що постійні вирази оцінюються під час компіляції, я вважаю, що більшість застосувань constexprфункцій взагалі не спричинять генерації коду ...
Kerrek SB

11
@KerrekSB constexprфункції потенційно оцінюються під час компіляції. Однак стандарт C ++ 14 усіяний тими, які, швидше за все, будуть викликані під час виконання. Наприклад:std::array<T,N>::at
однойменний

@Eponymous так, але лише найменша форма зменшиться як опкоди. наприклад: зв'язані чеки будуть оцінені під час збирання, оскільки їх кодовий шлях є const. Але повернене значення буде * (дані + зміщення)
v.oddou

16

constexprне означає inlineдля нестатичних змінних (C ++ 17 вбудованих змінних)

Хоча constexprце означає inlineдля функцій, він не має такого ефекту для нестатичних змінних, враховуючи C ++ 17 вбудованих змінних.

Наприклад, якщо взяти мінімальний приклад, який я розмістив у: Як працюють вбудовані змінні? і видаліть inline, залишаючи просто constexpr, тоді змінна отримує кілька адрес, що головне уникати вбудованих змінних.

constexpr статичні змінні, однак, неявно статичні.

Мінімальний приклад, що constexprпередбачає inlineфункції

Як згадувалося на веб- сайті: https://stackoverflow.com/a/14391320/895245, основний ефект 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.


3
До речі, оголошена змінна статичного класу constexprдосі є вбудованою. cppreference.com : Статична змінна члена (але не змінна область простору імен) оголошена constexprнеявно вбудованою змінною.
anton_rh

@anton_rh дякую, я цього правила не бачив, відповідь оновити.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

це не те, що говорить open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0386r0.pdf . в ньому йдеться про те, що constexpr має на увазі inline для змінних. без жодної згадки про різницю між областю простору імен.
v.oddou
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.