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指定子は暗黙指定しますか?constexprinlineinline

C ++ 11標準はそれを保証しますか?


5
「コンパイラは関数をインライン化しようとします」は、inline指定子が行うことではありません。(または、私はあなたの言い回しを誤解したかもしれません。)
Luc Danton 2013年

5
inline指定子は、もはやとは何か持っていないのインライン化を
K-BALLO

2
この質問inlineは、インライン化に直接関連する誤った仮定に基づいています。だから、何も、constexpr指定子が意味するものではありませんinlineよう、その意味で指定している感覚が存在しません。
Christian Rau 2013年

回答:


139

はい([dcl.constexpr]、C ++ 11標準の§7.1.5/ 2):「constexpr関数とconstexprコンストラクターは暗黙的にインライン化されます(7.1.2)。」

ただし、inline指定子は、コンパイラーが関数をインライン展開する可能性があるかどうかほとんど影響を与えないことに注意してください。ただし、これは1つの定義規則に影響し、その観点から、コンパイラーはconstexpr関数と同じ規則に従って関数を実行する必要がありinlineます。

また、constexpr暗黙の意味inlineに関係なくconstexpr、C ++ 11の関数のルールでは、インライン展開の優れた候補になることが多いほど単純である必要があることも追加する必要があります(主な例外は再帰的なものです)。しかし、それ以降、ルールは徐々に緩くなり、constexpr大幅に大きく複雑な関数に適用できるようになりました。


定数式がコンパイル時に評価されるという考えを考えると、constexpr関数のほとんどの使用はコード生成をまったく引き起こさないと思います...
Kerrek SB

11
@KerrekSB constexpr関数は、コンパイル時に評価される可能性があります。ただし、C ++ 14標準には、実行時に呼び出される可能性が高い標準が散らばっています。例:std::array<T,N>::at
Eponymous

@Eponymousはい、ただし最も縮小されたフォームのみがオペコードとして残ります。例:バインドされたチェックは、コードパスがconstであるため、ビルド時に評価されます。ただし、戻り値は*(data + offset)
v.oddou

16

constexprinline非静的変数を意味しません(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ファイルに含まれるためです。

しかし、に置き換えるinlineconstexprconstexprも意味するため、再び機能し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が変数のインラインを意味することを言います。クラススコープの名前空間スコープの違いについては触れられていません。
v.oddou
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.