22

私が読んでいるSTLコードは古いかもしれません...しかし、質問はC++テンプレート文法に関連しています。

質問は、この stl テンプレート関数を囲んでいます。

template<class T> std::destroy(T *p) {
    p->~T();
}

std::destroy(T *) 関数の特殊化が見つからないようです。したがって、テンプレート関数は「int」型に対して同じようにインスタンス化し、「int」のデストラクタを呼び出すように思えます。主張を明確にするために、std::destroy をエミュレートするこのサンプル コードを作成しました。この例では my_destroy と呼んでいます。

#include <iostream>
#include <stdio.h>
using namespace std;

template <class T> 
void my_destroy(T * pointer) {
    pointer->~T(); 
}
int main()
{
    int *a;
    //a->~int();        // !!! This won't compile.
    my_destroy<int>(a); // !!! This compiles and runs.
}

}

驚いたことに、この行はコンパイルされません。

a->~int();

しかし、この行はコンパイルされます:

my_destroy<int>(a);

my_destroy<int>(a)私の混乱は、それが同等のものとしてインスタンス化されると思ったa->~int();

より大きな文脈での質問に対して、STL コンテナーが<int>要素を消去するとき、どのように機能しstd::destroy()ますか?

4

3 に答える 3

33

a->~int();コンパイルされませんが、これは実行されることに注意してください。

typedef int INT;
int* a;
a->~INT();

標準から:

5.2.4p1pseudo-destructor-nameドットの後の使用。type-nameor 矢印 -> 演算子は、 orで示される非クラス型のデストラクタを表しdecltype-specifierます。結果は、関数呼び出し演算子 () のオペランドとしてのみ使用され、そのような呼び出しの結果は void 型になります。唯一の効果は、ドットまたは矢印の前の postfix-expression の評価です。

5.2p1 から:

pseudo-destructor-name:
  nested-name-specifier_opt type-name :: ~ type-name
  nested-name-specifier template simple-template-id :: ~ type-name
  nested-name-specifier_opt~ type-name
  ~ decltype-specifier

最後に、7.1.6.2p1:

type-name:
  class-name
  enum-name
  typedef-name
  simple-template-id

不思議なことに、intは構文的に a ではないtype-name(a であるsimple-type-specifier) ため、 を呼び出すことはできませんが~int()、 であり、呼び出すINTことはできます。

于 2013-07-19T21:45:27.367 に答える
4

クラス型 (非スカラー型) の場合、式

pointer->~T();

基本的には関数呼び出し (後置式) です。呼び出される関数を特定するには、その部分pointer->~Tを分析する必要があります。~Tis an id-expression IFFはclass-nameTであり、デストラクタ関数を識別します。

もちろん、intクラス名ではありません。しかし、Tがスカラー型を指定する型名である場合、同じ式が別の方法で解析されます部分全体は、疑似デストラクタ nameと呼ばれる特別な後置式pointer->~Tとして識別されます。次の式では、疑似デストラクタの呼び出しと見なされます ([expr.pseudo] のルールは、疑似デストラクタ名で他のことを行うことを禁じていますが、それを呼び出すことはできません)。()

intそれ自体は型名[dcl.type.simple] ではなく、単純型指定子です。

タイプ名:

  • クラス名
  • 列挙名
  • 型定義名
  • 単純なテンプレート ID

そのため、例のようにtypedef'dintまたはT(*) を使用できますが、int直接使用することはできません。その理由は、 seheによって十分に説明されています。

疑似デストラクタ呼び出しのルールは [expr.pseudo] で指定されています

(*) [temp.param]/3 から: 「識別子が省略記号の後に続かない型パラメーターは、その識別子typedef-name [...] と定義します」

于 2013-07-19T21:46:43.507 に答える
3

この言語により、これらのことがジェネリックプログラミングを可能にします。ただし、「まっすぐな」呼び出しは汎用コードではないため、失敗します。

別のそのようなケースは

template <typename T> void foo()
{
    T instance = T(); // default constructor
}

foo<int>(); // will work

あ、はい:

template <typename T> void foo()
{
    T* instance = new T(); // default constructor
    delete instance;      
}

Tはテンプレートのスコープ内の型名であるため、組み込みのプリミティブ型でも機能します。

于 2013-07-19T21:31:03.587 に答える