C ++ 11では、using
に使用した場合のキーワードtype alias
はと同じですtypedef
。
7.1.3.2
typedef-nameは、エイリアス宣言によって導入することもできます。usingキーワードに続く識別子はtypedef-nameになり、識別子に続くオプションのattribute-specifier-seqはそのtypedef-nameに付随します。typedef指定子によって導入された場合と同じセマンティクスを持っています。特に、新しいタイプを定義せず、type-idに表示されません。
Bjarne Stroustrupは実用的な例を提供します:
typedef void (*PFD)(double); // C style typedef to make `PFD` a pointer to a function returning void and accepting double
using PF = void (*)(double); // `using`-based equivalent of the typedef above
using P = [](double)->void; // using plus suffix return type, syntax error
using P = auto(double)->void // Fixed thanks to DyP
C ++ 11より前のusing
キーワードでは、メンバー関数をスコープに含めることができます。C ++ 11では、これをコンストラクターに対して行うことができます(別のBjarne Stroustrupの例):
class Derived : public Base {
public:
using Base::f; // lift Base's f into Derived's scope -- works in C++98
void f(char); // provide a new f
void f(int); // prefer this f to Base::f(int)
using Base::Base; // lift Base constructors Derived's scope -- C++11 only
Derived(char); // provide a new constructor
Derived(int); // prefer this constructor to Base::Base(int)
// ...
};
Ben Voightは、新しいキーワードや新しい構文を導入しないという根拠の背後にあるかなり良い理由を提供します。標準では、古いコードをできるだけ壊さないようにしています。これが、プロポーザルドキュメントImpact on the Standard
でDesign decisions
、などのセクションが表示され、それらが古いコードにどのように影響するかを示している理由です。提案が本当に良いアイデアのように見えても、実装が難しすぎたり、混乱しすぎたり、古いコードと矛盾したりするため、牽引力がない場合があります。
これは2003年のn1449の古い論文です。理論的根拠はテンプレートに関連しているようです。警告:PDFからのコピーによりタイプミスがある可能性があります。
最初におもちゃの例を考えてみましょう:
template <typename T>
class MyAlloc {/*...*/};
template <typename T, class A>
class MyVector {/*...*/};
template <typename T>
struct Vec {
typedef MyVector<T, MyAlloc<T> > type;
};
Vec<int>::type p; // sample usage
このイディオムの根本的な問題、およびこの提案の主な動機付けの事実は、イディオムがテンプレートパラメーターを推定できないコンテキストで表示することです。つまり、テンプレート引数を明示的に指定しないと、以下の関数fooを呼び出すことはできません。
template <typename T> void foo (Vec<T>::type&);
したがって、構文はやや醜いです。ネストは避け::type
たい次のようなものが望ましいでしょう:
template <typename T>
using Vec = MyVector<T, MyAlloc<T> >; //defined in section 2 below
Vec<int> p; // sample usage
「typedefテンプレート」という用語は特に避け、混乱を避けるために「using」と「=」のペアを含む新しい構文を導入していることに注意してください。ここではタイプを定義していないため、テンプレートパラメータを含むtype-id(つまり、型式)の抽象化。テンプレートパラメーターが型式の推定可能なコンテキストで使用される場合、テンプレートエイリアスを使用してテンプレートIDを形成するときはいつでも、対応するテンプレートパラメーターの値を推定できます。これについては後ほど説明します。いずれの場合も、Vec<T>
推測可能なコンテキストで動作する汎用関数を作成できるようになり、構文も改善されました。たとえば、fooを次のように書き換えることができます。
template <typename T> void foo (Vec<T>&);
ここで、テンプレートエイリアスを提案する主な理由の1つは、引数の演繹とへの呼び出しfoo(p)
が成功するようにしたことを強調します。
フォローアップペーパーn1489は、以下using
を使用する代わりに理由を説明していtypedef
ます。
テンプレートのエイリアスを導入するには、論文[4]で行われているように、キーワードtypedefを(再)使用することが推奨されています。
template<class T>
typedef std::vector<T, MyAllocator<T> > Vec;
その表記法には、型エイリアスを導入するためにすでに知られているキーワードを使用するという利点があります。ただし、エイリアスがタイプではなくテンプレートを指定するコンテキストでタイプ名のエイリアスを導入することがわかっているキーワードを使用することの混乱など、いくつかの欠点も表示されます。Vec
は型のエイリアスではないため、typedef-nameには使用しないでください。名前Vec
はファミリのstd::vector< [bullet] , MyAllocator< [bullet] > >
名前です。箇条書きはタイプ名のプレースホルダです。したがって、「typedef」構文は提案しません。一方、文
template<class T>
using Vec = std::vector<T, MyAllocator<T> >;
次のように読み取り/解釈できます。Vec<T>
今後は、の同義語として使用しますstd::vector<T, MyAllocator<T> >
。これを読むと、エイリアシングの新しい構文は合理的に論理的に思えます。
ここでは重要な違いがあると思います。型 s ではなくエイリアス es です。同じ文書からの別の引用:
エイリアス宣言は宣言であり、定義ではありません。別名宣言は、宣言の右側で指定された型の別名として、宣言型領域に名前を導入します。この提案の核心は型名のエイリアスに関係していますが、表記法は明らかに一般化して、名前空間のエイリアスの代替スペルまたはオーバーロードされた関数の名前のセットを提供できます(詳細については、✁2.3を参照してください)。[ 私のメモ:そのセクションでは、その構文がどのように見えるか、およびそれが提案の一部ではない理由について説明します。]文法生成のエイリアス宣言は、typedef宣言または名前空間エイリアス定義が受け入れられる場所であればどこでも受け入れられることに注意してください。
まとめusing
:
- テンプレートのエイリアス(またはテンプレートのtypedefs、前者は名前ごとに推奨)
- 名前空間のエイリアス(すなわち、
namespace PO = boost::program_options
とusing PO = ...
同等)
- 文書は言う
A typedef declaration can be viewed as a special case of non-template alias-declaration
。これは美的変更であり、この場合は同一と見なされます。
- スコープ(
namespace std
グローバルスコープなど)、メンバー関数、コンストラクターの継承
次のものには使用できません。
int i;
using r = i; // compile-error
代わりに:
using r = decltype(i);
オーバーロードのセットに名前を付ける。
// bring cos into scope
using std::cos;
// invalid syntax
using std::cos(double);
// not allowed, instead use Bjarne Stroustrup function pointer alias example
using test = std::cos(double);