記事ディレクトリ
問題の説明
オーバーロードされた関数がパラメーターに従って来ようとし、戻り値の型とは関係がないと言って、stackoverflowに問題を見つけました。ただし、次のテンプレート関数は戻り値の型が異なるだけで、なぜ正しいのですか?[1]を参照してください。
#include <iostream>
using namespace std;
template<typename T>
T add(double a, double b)
{
return static_cast<T>(a + b);
}
int main()
{
cout << add<int>(1.1, 1) << endl;
cout << add<double>(1.1, 1) << endl;
return 0;
}
このコードは正しいです。つまり、* add <int>(double、double)と add <double>(double、double)*のシンボルは異なります。次に、これはテンプレートコードの生成に関係し、実際には、テンプレートが使用されると、指定されたタイプのコード(テンプレートのインスタンス化)が生成されます。
誰かが詳細な回答をここに投稿しました:
戻り値の型は関数の前部の一部ではありません、C ++標準では次のように規定されています:defns.signature
(関数)名前、parameter-type-list、およびそれを囲む名前空間(存在する場合)
[注:署名は、名前のマングリングとリンクの基礎として使用されます。—エンドノート]
ただし、テンプレート関数の前部には、テンプレートパラメータdefns.signature.specが含まれています。
(関数)テンプレート特殊化⟩特殊化されたテンプレートの署名とそのテンプレート引数(明示的に指定されているか、推測されているかに関係なく)
質問はさておき、テンプレートのインスタンス化を見てみましょう。
テンプレートのインスタンス化
テストコードtest.cpp:
template < class T> T add(T a, T b){
return a+b;
}
void tmp(){
add<int>(10, 2);
}
int add(int a, int b)
{
return a + b;
}
- アセンブリコードを表示する
手順:
gcc -S -O1 test.cpp
コードは次のとおりです(一部)。
// 模板函数
_Z3addIiET_S0_S0_:
.LFB3:
.cfi_startproc
pushq %rbp
// 普通add函数
_Z3addii:
.LFB2:
.cfi_startproc
pushq %rbp
c ++ filtを使用して、次のように表示します。
[root@localhost template]# c++filt _Z3addIiET_S0_S0_
int add<int>(int, int)
[root@localhost template]# c++filt _Z3addii
add(int, int)
- clangの関数を使って以下の内容を取得すると、通常の関数とは異なる関数が生成されていることもわかります。
[root@localhost template]# clang++ -Xclang -ast-print -fsyntax-only compile2.cpp
template <class T = int> int add(int a, int b) {
return a + b;
}
template <class T> T add(T a, T b) {
return a + b;
}
;
void tmp() {
add<int>(10, 2);
}
int add(int a, int b) {
return a + b;
}
まとめ
- テンプレート関数は、異なるタイプをインスタンス化するための異なる関数コードを生成します
- テンプレート関数の関数の前にはテンプレートパラメータがあるため、名前とパラメータのタイプと番号が同じであっても、通常の関数と同じではありません
参考資料
[1] 戻り値の型のみに基づくテンプレート関数がC ++で機能するのはなぜですか?
[2] テンプレートのコンパイル
[3] C ++コンパイラによってインスタンス化されたテンプレートを確認できますか
[4] C ++コンパイラは各テンプレートタイプのコードを生成しますか?
[5] どうすれば、C ++コンパイラーが、発行されたマシンコードを検査する以外に何かを実装するのを見つけることができますか?