テンプレートでインラインキーワードを使用しても意味がありますか?


119

テンプレートはヘッダー内で定義されており、コンパイラーは関数のインライン化が有利であるかどうかを判断できるので、意味がありますか?最近のコンパイラーは関数をインライン化するタイミングをよく知っており、inlineヒントを無視していると聞きました。


編集:両方の回答を受け入れたいのですが、これは不可能です。問題を解決するために、私はフレネルの回答を受け入れています。ほとんどの票を獲得し、彼は正式に正しいからですが、コメントで述べたように、私は別の観点から、パピーコンポーネント10の回答も正しいものと見なします。

問題はC ++のセマンティクスにあり、inlineキーワードとインライン化の場合は厳密ではありません。phresnelは「それを意味する場合はインラインで書き込む」と言いますが、実際の意味inlineは、元の意味から、パピーが言うように「コンパイラーがODR違反について噛み付くことを停止する」というディレクティブに発展したため、明確ではありません。

回答:


95

それは無関係ではありません。いいえ、すべての関数テンプレートがinlineデフォルトであるわけではありません。標準は、明示的な特化([temp.expl.spec])でそれについても明示的です

以下を用意してください。

a.cc

#include "tpl.h"

b.cc

#include "tpl.h"

tpl.h(明示的な特殊化から取得):

#ifndef TPL_H
#define TPL_H
template<class T> void f(T) {}
template<class T> inline T g(T) {}

template<> inline void f<>(int) {} // OK: inline
template<> int g<>(int) {} // error: not inline
#endif

これをコンパイルして、他の出来事:

g++ a.cc b.cc
/tmp/ccfWLeDX.o: In function `int g<int>(int)':
inlinexx2.cc:(.text+0x0): multiple definition of `int g<int>(int)'
/tmp/ccUa4K20.o:inlinexx.cc:(.text+0x0): first defined here
collect2: ld returned 1 exit status

inline明示的なインスタンス化を行うときに言及しないと、問題が発生する可能性があります。

要約すると、完全に特殊化されていない関数テンプレート、つまり少なくとも1つの不明な型を含むテンプレートの場合、を省略してinlineもエラーは発生しませんが、そうではありませんinline。完全な特殊化、つまり既知のタイプのみを使用するものについては、省略できません。

提案された経験則inlineもしあなたがそれを意味し、ただ一貫しているなら書く。それはあなたができるからといって、そうするべきかどうかについてあなたがあまり考えないようにします。(この経験則は、Vandevoorde / JosuttisのC ++テンプレート:完全ガイドに準拠しています)。


2
本当のことを書いてもよかったのに。しかし、そのように見えても、それはインライン性を意味するものではありません。VandevoordeとJosuttisは、C ++テンプレート
Sebastian Mach

43
明示的な特殊化はテンプレートではありません。
パピー

2
@DeadMG:それでも、ルックアップ時の完全な特殊化よりも通常の関数の方が好ましいので、それらがテンプレートでもテンプレートでもない場合、それらは何ですか?
セバスチャンマッハ

13
この答えは間違っています。テンプレートの明示的な特殊化は関数であり、テンプレートではありません。inline特化したテンプレートをでマークしたからといって、その機能は成り立ちませんinline。したがってinline、テンプレートは完全に無関係です。その関数がそうであるかどうかはinline、テンプレートの特殊化を介して生成されることとは何の関係もありません(そして、これを使用する場合に対処するより良い答えがありますinline)。以下の@Puppyの答えは正しいですが、これは正しくありません。inlineテンプレートへの追加は無関係であり、clang-tidy実際には削除されます。
gnzlbg 2017

6
また、この例では、通常の関数(テンプレートとは関係のない動作)のODR問題を示しています。上映しようとするには inline無関係であるされていないが、例としては、明示的に専門のケースカバーすべきであるtemplate<> void f<>(int) {} なしにinlineキーワードを。ただしinline、テンプレートにマークを付けるかどうかinlineは関係がないため、テンプレートの指定子を変更しても違いはありません。
gnzlbg 2017

34

それは無関係です。すべてのテンプレートは既にありますinline-2012年の時点で、inlineキーワードの唯一の使用は、コンパイラーがODR違反について不平を言うのを停止することです。あなたは絶対に正しいです-あなたの現在の世代のコンパイラはそれ自体で何をインライン化するかを知っており、おそらく翻訳単位の間でもそうすることができます。


11
標準では、すべてのテンプレートがインラインであるとは規定されていません。
セバスチャンマッハ

16
@phresnel:ただし、テンプレートの意味はinline-marked関数と同じです(つまり、複数の同等の定義がリンカーに渡され、リンカーが1つを選択します)。インライン化ではなく、それがinlineキーワードの実際の機能です。
Ben Voigt

2
@BenVoigt:ODRの意味について知っていinlineます。たぶん以下の私の答えを覗いてみてください(または選択した並べ替えに応じて、それ以上)特殊化されていないテンプレートについては、もちろんあなたは正しいですが、正式には同じではありません。
セバスチャンマッハ

3
@DeadMG:C ++では、関数テンプレートをヘッダーファイルに実装する必要はありません。どこにでも実装できます。これを反映するために、inlineインラインになるはずのタグを付けることをお勧めします。通常は違いはありませんが、標準的には同じではなく、すべてインラインではありません。私は「それは無関係」と言ってあなたのスタンスを受け入れますが、標準では、すべてのテンプレートがインラインであるわけではなく、あたかもC ++ユーザーであるかのように見えます。
セバスチャンマッハ

7
明示的な専門化がテンプレートではないという、受け入れられた回答に対するコメント(もちろん、そう言われたで明らかです...)は、おそらくこのページで最も役立つものです。回答に追加していただけませんか?
カイルストランド

6

あなたが示唆したように、inlineはコンパイラへのヒントであり、それ以上のものはありません。それを無視するか、実際にはインラインとしてマークされていない関数をインライン化するかを選択できます。

使用してinline、各コンパイル単位は、同じテンプレートクラスの別のオブジェクトを作成するであろうと、問題の周りを取得する(貧しい)な方法であることが使用するテンプレートとその希望、リンク時に重複問題の原因。を使用してinline(私が思うに)名前のマングリングと、リンク時の名前の衝突を回避できますが、コードが大幅に肥大化します。  

マーシャル・クラインがここで私よりもよく説明しています


@Xeo:以前はそうではありませんでした。ここをチェックしてください:gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/…それは最近変更されたと思います。そのため、私は過去形で話していました。
コンポーネント10

2
@Xeo:関数テンプレートは常にインラインであると述べている標準の部分を私に指摘できますか?なぜなら、そうではないからです。
Sebastian Mach、

@phresnel:おもしろい、私はそれを標準で読んだと誓うことができる。多分私はそれを関数テンプレートがODRから免除されるという事実と混同しました(§14.5.5.1 p7 & p8)。私の悪い、私は間違ったコメントを削除しました。
Xeo

@コンポーネント10なぜコンパイルの問題を回避するのに不適切な方法だと思うのか
Kapil
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.