C++ での vs typedef の使用
この記事では、typedef
と using
を区別しようとします。 C++ の関数型プログラミングでは、これらのキーワードの目的とセマンティクスは同じであるため、両者の違いはごくわずかです。
この記事では、読者がこれらのキーワードの機能と typedef
と using
の違いを確実に理解できるように、さまざまなコンテキストでキーワードについて説明します。
C++ の using
キーワード
typedef
とは対照的に using
キーワードを理解することは、typedef
と using
の違いを学ぶために重要です。
オブジェクトをプログラムの現在のスコープに移動するために使用されます。 これは、C++ から指定子を取り込むためのアクセス ツールとして使用できることを意味します。
例を見てみましょう。
#include <iostream>
int main() {
using std::cout;
using std::string;
int a = 56;
cout << a;
return 0;
}
出力:
56
ここでは、キーワード using
を使用して、名前空間から cout
や string
などの指定子にアクセスし、それらをプログラムのスコープ内に取り込みます。
同様に、using
を使用して他の指定子にアクセスしたり、using namespace as std
を使用して名前空間全体を取得したりすることもできます。 これにより、名前空間全体がプログラムのスコープ内に移動し、すべての指定子に std
を使用してアクセスできます。
using
キーワードの例
以下のコード スニペットは、パラメーターとして 2つの整数変数 a
と b
を持つパブリック メソッド add
を持つクラス Parent
を作成します。 メソッド add
は、2つの変数の合計を出力します。
child
クラスは保護モードで Parent
クラスを派生させます。つまり、Parent
クラスのすべてのメンバーは保護されたメンバーとして継承されます。
main
関数内では、Child
クラスを使用してオブジェクトのインスタンスが作成され、メソッド add
はそのオブジェクトを使用して派生します。
#include <iostream>
using namespace std;
class Parent {
public:
void add(int a, int b) { cout << "Result = " << a + b << endl; }
};
class Child : protected Parent {
public:
using Parent::add;
};
int main() {
Child obj;
obj.add(15, 30);
return 0;
}
出力:
Result = 45
ここで、キーワード using
は、Child
クラスを介して Parent
クラスからメソッド add
にアクセスするために使用されます。
C++ で using
キーワードを使用してループを実装する
ここでの構文は、using
を介して for
ループを実装しています。
for (using i = int; i{} != 0;) {
i++;
}
範囲ベースのループの場合、using
は次のように使用されます。
std::vector<int> v{1, 2, 3};
for (using Foo = int; Foo f : v) {
(void)f;
}
C++ でのusing
キーワードを使用したSwitch Case
ステートメント
switch case
ステートメントでは、using
は次のように実装されます。
if (using Foo = int; true) {
(void)Foo{};
}
switch (using Foo = int; 0) {
case 0:
(void)Foo{};
}
C++ の typedef
キーワード
キーワード typedef
には、カスタム名を使用して型に名前を付ける機能があります。 これは、既存のデータ型にエイリアスを導入できることを意味します。
typedef
と using
の主な違いは、このセクションで確認できます。
以下のプログラムは、この概念を明確に説明しています。
#include <stdio.h>
#include <string.h>
typedef struct Books {
char title[50];
char author[50];
char subject[100];
int book_id;
} Book;
4つの変数を持つ struct
クラス Book
が導入されています。 これら 4つの変数は、typedef
を使用して新しいデータ型として構造化され、この型には Book
という名前が付けられます。
main
クラス内で、新しいオブジェクトを作成して型 Book
にアクセスし、その変数を取得する必要があります (必要に応じて)。
個々の変数が構文 object_name.variable_name,"input"
を使用して呼び出されていることがわかります。 これらの変数にデータが与えられると、呼び出しに使用されたのと同じメソッドを使用して出力されます。
int main() {
Book book;
strcpy(book.title, "Typedef vs using");
strcpy(book.author, "JS");
strcpy(book.subject, "C Programming");
book.book_id = 6495407;
printf("Book title : %s\n", book.title);
printf("Book author : %s\n", book.author);
printf("Book subject : %s\n", book.subject);
printf("Book book_id : %d\n", book.book_id);
return 0;
}
出力:
Book title : Typedef vs using
Book author : JS
Book subject : C Programming
Book book_id : 6495407
C++ で typedef
キーワードを使用したループ
ループの反復中に、typedef
は構文 for (typedef (datatype)Function; Function{} != 0;)
を使用して定義されます。
for (typedef int i; i{} != 0;) {
i++;
}
範囲ベースのループ反復中、typedef
は次のように使用されます。
std::vector<int> v{1, 2, 3};
for (typedef int Foo; Foo f : v)
// ^^^^^^^^^^^^^^^ init-statement
{
(void)f;
}
2 次元行列内の範囲ベースのループの別の例:
for (typedef struct {
int x;
int y;
} P;
auto [x, y] : {P{1, 1}, {1, 2}, {3, 5}}) {
(void)x;
(void)y;
}
C++ でtypedef
キーワードを使用したSwitch Case
ステートメント
以下に示すように、typedef
キーワードは switch case
ステートメントで使用されます。
if (typedef int Foo; true) {
(void)Foo{};
}
switch (typedef int Foo; 0) {
case 0:
(void)Foo{};
}
テンプレートの定義における typedef
と using
の使用
関数型プログラミングのコンテキストから、typedef
と using
の違いを確認しました。 理解する必要があるもう 1つの重要な部分は、テンプレートの定義方法です。
C++ では、typedefs
にテンプレートのエイリアスを定義する機能がありました。 非常に長い間使用されてきましたが、typedef
のセマンティクスがテンプレートとうまくいかないことが観察されました。
この問題を解決するために、typedef
は減価償却され、using
が行われました。
以下の例では、typedef
と using
の違いについて、テンプレートの定義のコンテキストで説明しています。
C++ での typedef
を使用したエイリアス テンプレート
例 1:
ここでは、長さ x
とテンプレートを使用してエイリアスを与える必要がある静的な幅を持つように長方形が定義されています。
<size_t N>
は、長方形の長さを格納するテンプレートです。 対照的に、Dimension
は typedef
を使用してエイリアス Rectangle
が与えられるオブジェクトです。
ここで、コードは Rectangle
を Dimension<N,1>
のエイリアスに割り当てます。これは、オブジェクト Dimension
が長さと幅を持つことを意味します。 ここで、オブジェクト Dimension
は、長さ <size_t N>
と幅 1
を持ちます。
template <size_t N>
struct Rectangle {
typedef Dimension<N, 1> type;
};
これは、プログラマが単一の値パラメータ size_t N
を Rectangle
に渡す必要があることを意味します。 コンパイラは渡されたものを長さとして受け取り、幅は 1
に設定されます。
構文 Rectangle<5>::int
は整数値 5
をオブジェクト Dimension
に渡し、Dimension<5,1>
を書くのと同じになります。
上記の例は、typedef
が廃止されたため、最近の C++ バージョンでは使用されなくなりました。 using
を使用してテンプレートにエイリアスを与えることは、上記の例よりも簡単です。
例 2:
テンプレート クラス Match
は、以下のコード スニペットで定義されています。 この Match
クラスには、エイリアス テンプレート MatchBox
が与えられます。
Match
クラスも将来的に置き換えることができます。
template <typename U>
struct Match {};
template <typename U>
struct MatchBox {
typedef Match<U> type;
};
MatchBox<int>::type variable;
template <typename V>
struct bar {
typename MatchBox<V>::type_var_member;
}
型の抽象化が必要であるが、将来提供できるようにテンプレート パラメータも保持する必要がある場合、このようなコードを記述する必要があります。
C++ での using
キーワードによるテンプレートのエイリアス
例 1:
このセクションでは、テンプレートのコンテキストにおける typedef
と using
の違いについて説明します。 ここで、テンプレート <size_t N>
は typedef
の例 1 で使用したものと同じで、長方形の長さを格納します。
struct
を使用する代わりに、エイリアス Rectangle
がキーワード using
によってオブジェクト Dimension
に割り当てられます。 これは、オペレーターが割り当てられるのと同じ方法で行われます。
エイリアスを割り当てた後のエイリアス Rectangle
は、縦と横にそれぞれ N
と 1
を持ちます。
template <size_t N>
using Rectangle = Dimension<N, 1>;
using
はより洗練されたバージョンのエイリアシングを提供し、記述と実装がより簡単であることがわかります。 ここで使用されている構文は、従来の変数と演算子の割り当てに似ているため、読みやすさが改善されたようです。
例 2:
この例では、テンプレート パラメーターを開いたままにして、指定できるようにします。 typedef
の例では、このプロセスに複数行のコードが必要でした。 しかし、using
構文はコードと複雑さを軽減します。
template <typename U>
using MatchBox = Match < U
MatchBox<int>
variable;
template <typename V>
struct bar {
MatchBox<V> _var_member;
}
using
キーワードを使用してテンプレートのエイリアスを定義するのは、typedef
よりもはるかに簡単です。これは、プロセスが変数のコピー割り当てに似ているためです。
まとめ
この記事では、C++ におけるキーワード typedef
と using
の違いについて説明します。 読者は、これらのキーワードの基本的な違いと、さまざまなプログラミング コンテキストでの実装を理解できます。
この記事が学習の旅に役立つことを願っています。