これが私のコードです:
#include <iostream>
class MyBaseClass
{
public:
static int StaticInt;
};
int MyBaseClass::StaticInt = 0;
template <int N> class MyClassT : public MyBaseClass
{
public:
MyClassT()
{
StaticInt = N;
};
};
template <int N> static MyClassT<N> AnchorObjT = {};
class UserClass
{
friend void fn()
{
std::cout << "in fn()" << std::endl; //this never runs
(void)AnchorObjT<123>;
};
};
int main()
{
std::cout << MyBaseClass::StaticInt << std::endl;
return 0;
}
出力は次のとおりです。
123
...MyClassT()
コンストラクターが呼び出されたことfn()
がないにもかかわらず、コンストラクターが呼び出されたことを示します。
上でテストgcc
とclang
で-O0
、-O3
、-Os
とさえ-Ofast
このプログラムは、C ++標準に従って未定義の動作をしますか?
言い換えると、後のバージョンのコンパイラーfn()
がそれが呼び出されないことを検出できた場合、コンストラクターを実行すると同時にテンプレートのインスタンス化を最適化できますか?
このコードをどういうわけか決定論的にすることはできますか?つまり、コンストラクターを強制的に実行することがfn
できますか?関数名またはテンプレートパラメーター値を123
外部で参照することはありUserClass
ませんか?
テンプレートのインスタンス化はコードの関数であり、動的な実行時条件の関数ではありません。単純な例として:
template <typename T> void bar();
void foo(bool b) {
if (b) {
bar<int>();
} else {
bar<double>();
}
}
bar<int>
とbar<double>
は両方ともここでインスタンス化されます。呼び出されたことがないfoo
場合や、foo
でのみ呼び出された場合でも同様ですtrue
。
変数テンプレートの場合、具体的には、ルールは[temp.inst] / 6です。
変数テンプレートの特殊化が明示的にインスタンス化または明示的に特殊化されていない限り、変数テンプレートの特殊化は、変数定義の存在を必要とするコンテキストで参照される場合、または定義の存在がプログラムのセマンティクスに影響を与える場合に暗黙的にインスタンス化されます。
あなたの機能では:
friend void fn() { (void)AnchorObjT<123>; };
AnchorObjT<123>
定義を必要とするコンテキストで参照されているため(fn()
呼び出されたかどうかに関係なく、この場合は呼び出すことも可能です)、インスタンス化されます。
ただし、AnchorObjT<123>
はグローバル変数であるため、そのインスタンス化は、以前に構築されたオブジェクトがあることを意味します。main()
入力するまでにmain()
、AnchorObjT<123>
のコンストラクターが実行され、に設定さStaticInt
れ123
ます。fn()
このコンストラクターを呼び出すために実際に実行する必要はないことに注意してください-fn()
ここでの役割は、変数テンプレートをインスタンス化することだけであり、そのコンストラクターは他の場所で呼び出されます。
123の印刷は、予想される正しい動作です。
言語ではグローバルオブジェクトAnchorObjT<123>
が存在する必要がありますが、リンカはオブジェクトへの参照がないため、オブジェクトが存在する可能性があることに注意してください。実際のプログラムがこのオブジェクトでより多くのことを行うと仮定すると、それが存在する必要がある場合は、リンカーがそれを削除しないようにするために、より多くのことを行う必要があります(たとえば、gccにはused
属性があります)。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加