web-dev-qa-db-ja.com

テンプレートパラメータに 'class'または 'typename'を使用しますか?

可能な重複:
テンプレート内のキーワード 'typename'と 'class'のC++の違い

C++で関数テンプレートやクラステンプレートを定義するとき、これを書くことができます。

template <class T> ...

または、これを書くことができます:

template <typename T> ...

一方を他方よりも優先させる正当な理由はありますか?


私は最も人気のある(そしておもしろい)答えを受け入れました、しかし本当の答えは「いいえ、一方を他方よりも好む理由はありません」のようです。

  • それらは同等です(以下に記載されている場合を除く)。
  • typenameを常に使う理由があります。
  • classを常に使う理由があります。
  • 両方を使用する理由がある人もいます。
  • どちらを使うのか気にしない人もいます。

ただし、テンプレートテンプレートパラメータの場合は、classの代わりにtypenameを使用する必要があります。下記の user1428839の回答 を参照してください。 (ただし、この特定のケースは好みの問題ではなく、言語の要件です。)(これもc++17によって変わります)

562

スタンリップマンはこれについて話しました こちら 。面白いと思いました。

Summary:Stroustrupは、元々classを使用してテンプレートにタイプを指定し、新しいキーワードの導入を避けました。委員会の何人かは、このキーワードの過負荷が混乱を招くことを心配した。その後、委員会は新しいキーワードtypenameを導入して、構文のあいまいさを解決し、混乱を減らすためにテンプレートタイプの指定にも使用することを決定しましたが、下位互換性のために、classはそのオーバーロードされた意味を維持しました。

387
itsmatt

Scott Myersによると、Effective C++(3rd ed。)item 42(もちろん、これは究極の答えであるに違いない) - 違いは「何もない」。

Tが常にクラスになることが予想される場合は "class"を使用し、他のタイプ(int、char *その他)が予想される場合は "typename"を使用することをお勧めします。使い方のヒントと考えてください。

298
DarenW

上記の記事すべてに加えて、classキーワードの使用 です 扱うときは強制的に(C++ 14まで) テンプレートテンプレート パラメータ、例:

template <template <typename, typename> class Container, typename Type>
class MyContainer: public Container<Type, std::allocator<Type>>
{ /*...*/ };

この例では、typename Containerはコンパイラエラーを生成します。

error: expected 'class' before 'Container'
144
JorenHeit

私は、オーバーロードされたキーワードのファンではないので、typenameを使用することを好みます(jeez - staticは、さまざまなコンテキストに対していくつの異なる意味を持ちますか?)。

47
Michael Burr

そこにの違いがあります、そしてあなたはclassよりtypenameを選ぶべきです。

しかし、なぜ?

typenameはテンプレートテンプレートの引数には無効です。そのため、一貫性を保つためにclassを使用する必要があります。

template<template<class> typename MyTemplate, class Bar> class Foo { };    //  :(
template<template<class>    class MyTemplate, class Bar> class Foo { };    //  :)
15
Mehrdad

Mike B に応答して、テンプレート内では 'typename'はオーバーロードされた意味を持ちますが、 'class'はそうしますそうではありません。このチェックされた整数型の例を見てください。

template <class IntegerType>
class smart_integer {
public: 
    typedef integer_traits<Integer> traits;
    IntegerType operator+=(IntegerType value){
        typedef typename traits::larger_integer_t larger_t;
        larger_t interm = larger_t(myValue) + larger_t(value); 
        if(interm > traits::max() || interm < traits::min())
            throw overflow();
        myValue = IntegerType(interm);
    }
}

larger_integer_tは従属名なので、パーサーがlarger_integer_tが型であることを認識できるようにするには、 'typename'を先に付ける必要があります。一方、classはそのようなオーバーロードされた意味を持ちません。

それは……あるいは私はただ怠け者です。私は 'typename'よりはるかに頻繁に 'class'をタイプします、そしてそれ故にそれがタイプすることがはるかに簡単であるとわかります。あるいは、私がOOコードを書きすぎたというサインかもしれません。

9
Aaron

純粋な歴史です。 Stan Lippmanからの引用

2つのキーワードの理由は歴史的なものです。元のテンプレート仕様では、Stroustrupは既存のプログラムを壊す可能性のある新しいキーワードを導入するのではなく、既存のクラスキーワードを再利用して型パラメータを指定しました。新しいキーワードが考慮されなかったというわけではありません - それがその潜在的な混乱を考えると必要であると考えられなかったということだけです。そしてISO-C++標準までは、これが型パラメータを宣言する唯一の方法でした。

しかし、classではなくtypenameを使うべきです。詳細についてはリンクを参照してくださいが、次のコードについて考えてください。

template <class T>
class Demonstration { 
public:
void method() {
   T::A *aObj; // oops ...
};
9
user306683

それはまったく問題ではありませんが、classはTがクラスにしかなれないように見えますが、もちろんどんな型でもかまいません。だからtypenameはもっと正確です。一方、ほとんどの人はクラスを使用しているので、一般的に読みやすくなっています。

7

私の知る限りでは、どちらを使用してもかまいません。これらはコンパイラから見ると同等です。好きな方を使用してください。私は通常クラスを使います。

1
Grant Limberg