web-dev-qa-db-ja.com

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関数に渡された場合、コンパイラがinlineinline指定子が宣言に置かれたかのような関数?

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

82
Vincent

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

ただし、inline指定子は、コンパイラがインラインで関数を展開する可能性があるかどうかに非常に少し(もしあれば)効果があることに注意してください。ただし、1つの定義ルールに影響します。その観点から、コンパイラはconstexpr関数とinline関数と同じ規則に従う必要があります。

また、constexprinlineを意味するかどうかに関係なく、C++ 11のconstexpr関数の規則では、インラインの適切な候補となるほど十分に単純であることが必要でした。拡張(主な例外は再帰的なものです)。ただし、それ以降、ルールは次第に緩くなってきているため、constexprを大幅に大きく複雑な関数に適用できます。

122
Jerry Coffin

constexprは、変数のinlineを意味しません(C++ 17インライン変数)

constexprは関数に対してinlineを意味しますが、C++ 17インライン変数を考慮すると、変数に対してはその効果はありません。

たとえば、私が投稿した最小限の例: インライン変数はどのように動作しますか? を削除してinlineを削除し、constexprだけを残すと、変数は複数のアドレスを取得します。これはインライン変数が回避する主なものです。

constexprが関数のinlineを意味する最小限の例

https://stackoverflow.com/a/14391320/895245inlineの主な効果はインラインではなく、関数の複数の定義を許可することです。 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

shared_funcからinlineを削除すると、リンクは次のように失敗します。

multiple definition of `shared_func()'

ヘッダーが複数の.cppファイルに含まれるためです。

ただし、inlineconstexprに置き換えると、constexprinlineを意味するため、再び機能します。

GCCは、ELFオブジェクトファイルでシンボルをウィークとしてマークすることにより、それを実装します。 C++ヘッダーファイルに実装を含めるにはどうすればよいですか?

GCC 8.3.0でテスト済み。