JosuttisとVandevoordeのよく知られたテンプレートの本C++ Templates: The Complete Guideでは、関数テンプレートのオーバーロードに関する詳細について説明しています。私が構築し、同じコードをコンパイルするとき、しかしJosuttisから:特定の型を与えられた同じ関数シグネチャにインスタンス化する異なるテンプレート関数は、ODR無効になりますか?
This program is valid and produces the following output:
(Note: Output shown below)
:
関数シグネチャの議論に関連し、その例の一つでは、とオーバーロードされた関数テンプレートは、彼らは、次の用語で記述したコードを提示しますVisual Studio 2010では、別の結果が得られます。これにより、VS 2010コンパイラが間違ったコードを生成しているか、Josuttisがコードが有効であると間違っていると考えられます。
ここにコードがあります。 (Josuttis氏2003年、12.2.1)
// File1.cpp
#include <iostream>
template<typename T1, typename T2>
void f1(T2, T1)
{
std::cout << "f1(T2, T1)" << std::endl;
}
extern void g();
int main()
{
f1<char, char>('a', 'b');
g();
}
...
// File2.cpp
#include <iostream>
template<typename T1, typename T2>
void f1(T1, T2)
{
std::cout << "f1(T1, T2)" << std::endl;
}
void g()
{
f1<char, char>('a', 'b');
}
(2つのテンプレート関数定義の型引数の逆転に注意してください。注また、この逆転は時に影響を与えないこと彼らは、このコード例では2つの機能f1()
ためのものであるように、2つの型引数は、同じである)
Josuttis氏によると:。
This program is valid and produces the following output:
f1(T2, T1)
f1(T1, T2)
私は、コンパイラ/リンカは区別することが可能であるかと思いまして、さらに
f1(T1, T2)
f1(T1, T2)
:
私は構築およびVisual Studio 2010のコンパイラでは、変わらず同じコードを実行は、ここに私の結果であり、ファンクションf1
はfile1.cppでインスタンス化され、ファンクションf1
はfile2.cppでインスタンス化されているので、コンパイラはこれらの関数がテンプレートから作成されたという知識のすべてを取り去り、関数シグネチャ自体の情報(私は考える):void (char, char)
これはf1
の関数で同じです。
機能シグネチャが2つの翻訳単位で同じなので、これはOne Definition Rule(ODR)の違反の例であると考えられますので、C++は無効です。
しかし、私がちょうど指摘したように、JosuttisとVandevoordeは、これが有効で C++であると主張しています。
しかし、同じコードの私のコンパイルされたバージョンは、異なる結果が得られるので、Josuttis氏が出力されていると主張するよりも、これはVS 2010のいずれかが不正なコードを生成している、またはJosuttis氏は、この場合は不正確であることを示す指標(すなわちのようです、コードは無効であり、ODRに違反しています)。
JosuttisとVandevoordeは間違っていますか、VS 2010の出力が正しくありませんか?または、VS 2010の出力と、Josuttisの出力との差異を説明する他の説明がありますか?
f1()
が呼び出された時点でVS 2010の逆アセンブリを表示することは重要です。
(直接main()
以内)f1()
の最初の呼び出し:
(g()
内から)f1()
の第二の呼び出し:
注f1()
のアドレスそのどちらの場合もコンパイラによって選択されるのは同じです - 13E11EAh。実際、コンパイラは2つのインスタンス化された関数のシグネチャを区別できないことを示しています。これはODRが違反しているため、コードはで無効です。C++であり、Josuttisには誤りがあります。しかしそれはちょうどその兆候です。知りません。
(私は本ウェブサイト上の正誤表をチェックして、この例の言及がない。)コメントからのリクエスト毎の
補遺、私はのために、.MAPファイルから関連出力を添付していますマングルされた名前を示し、このプログラムは、/ f1
に使用されている(S)
今の質問は答えていることを補遺2 - Josuttis氏の本が正しいか - 私はあることに注意したいですJosuttisテキストでは、同じセクション(12.2.1)に、ユニークな関数シグネチャを決定するものを明示的に示しています。には、テンプレートアスペクトが含まれています。
(関数シグネチャを定義する他のものの中でも)TRANSLATION UNITは関数シグニチャの一部です。テンプレート関数の場合は、RETURN TYPEは関数シグネチャの一部であり、
.6です。関数が関数テンプレートから生成されている場合は、テンプレートパラメータとテンプレート引数。
したがって、明らかです。テンプレート情報は、関数テンプレートがインスタンス化された後でも、コンパイラ/リンカーが(私の質問のコード例の場合のように)テンプレートに必要な特別な規則に従うために、コンパイラによって維持され、追跡されなければなりません。
問題の機能に実際にマングルされた名前を追加することは非常に便利です。 –
@Pedroどうすれば入手できますか?私は今それを得る方法を見るために見ていきます... –
これについてこのように考えてみましょう:すべてのテンプレートを1つのファイルに含めた場合、コードは正確ではありません(特殊化があいまいなので)。そのため、コードを別のファイルに分割するだけで、コードが正しくなるべきではありません。 –