C言語・C++におけるコンパイラエラー C2903 の原因と対策について解説
コンパイラ エラー C2903は、C言語およびC++のソースコードで、テンプレートではないシンボルを明示的なテンプレートインスタンス化として記述した場合に発生するエラーです。
たとえば、N::template Y y;
のように、テンプレートではないクラスに対して template
キーワードを誤って使用するとエラーとなります。
正しいテンプレート記述を採用することで解消できます。
C2903エラーの定義と概要
このエラーは、C言語やC++において、テンプレートではないシンボルをテンプレートとして明示的にインスタンス化しようとする場合に発生するエラーです。
具体的には、プログラマが意図せずに「template」キーワードを誤った場所に使用してしまった場合に、このエラーが発生します。
エラー内容には、「’identifier’ : シンボルがクラス テンプレートでも関数テンプレートでもありません」と表示され、対象のシンボルがテンプレートでないにも関わらず、テンプレートとして扱おうとしたことを示します。
エラーの発生条件
C2903エラーが発生する条件は、以下のようなケースが挙げられます。
- テンプレートでないクラスや関数に対して、テンプレート化するための記述をしてしまった場合
- ネームスペース内で、通常のクラスや関数に対して不適切に「template」キーワードを付けた場合
例えば、以下のコードはテンプレートではないクラスY
に対して「template」キーワードを付けてしまっており、C2903エラーとなります。
#include <iostream>
namespace N {
template <class T>
class X {
// テンプレートクラスの定義
};
class Y {
// 通常のクラス定義
};
}
int main() {
// 以下の記述は、Yがテンプレートではないためエラーとなります
// N::template Y instance; // コメントアウトしてあるが、この記述でC2903エラーが発生
N::X<N::Y> instance; // 正しい記述例
std::cout << "X<N::Y> のインスタンスが生成されました" << std::endl;
return 0;
}
この例では、N::template Y
という記述によりエラーとなる点を確認できます。
正しくは、テンプレートクラスであるX
に対してインスタンス化する形となります。
エラーコードC2903の意味
エラーコードC2903は、基本的にシンボルがテンプレートとして認識されない場合に発生します。
つまり、コンパイラは以下のような状況を検出した場合にこのエラーを報告します。
- テンプレートではない型や関数に対して、テンプレートの実体化を試みている
- ネームスペースやスコープの中で、正確な宣言内容と一致しない利用方法をしている
このエラーが発生すると、プログラムが意図した動作をしなくなるため、記述の見直しが必要です。
発生原因の解説
C2903エラーの発生原因は、主にテンプレートと非テンプレートの区別が不十分な場合に発生します。
プログラム内での意図と実際のシンボルの性質が乖離している場合が原因です。
テンプレートと非テンプレートの区別
C++ではテンプレートと通常のクラスや関数で扱い方が異なるため、どちらであるかを正確に把握する必要があります。
テンプレートに対しては、コンパイラが型を展開してインスタンス化を行いますが、通常のクラスや関数はそのような処理を行いません。
明示的インスタンス化の誤用例
誤って通常クラスに「template」キーワードを付ける例として、以下のコードが挙げられます。
#include <iostream>
namespace N {
class Y {
// 通常のクラス
};
}
int main() {
// 以下の記述は、YがテンプレートではないためC2903エラーが発生します
// N::template Y object; // コンパイルエラーになるコード例
std::cout << "Y クラスは通常クラスです" << std::endl;
return 0;
}
この例では、クラスY
は通常のクラスですが、「template」キーワードを付けた場合にエラーとなります。
正しい記述方法との比較
正しい記述方法は、テンプレートとして定義されたシンボルにのみ「template」キーワードを使用することです。
以下は正しい記述例になります。
#include <iostream>
namespace N {
template <class T>
class X {
// テンプレートクラスの定義
};
class Y {
// 通常のクラス定義
};
}
int main() {
// 正しい記述:テンプレートXをYでインスタンス化
N::X<N::Y> object;
std::cout << "X<N::Y> のインスタンスが生成されました" << std::endl;
return 0;
}
この例では、テンプレートクラスX
に対して正しい記述方法でインスタンス化しており、C2903エラーを回避することができます。
コンパイラエラーへの対策
C2903エラーを解消するためには、テンプレート記述のポイントを正しく把握し、コード修正を行うことが大切です。
テンプレート記述のポイント
- テンプレートとして定義されたシンボルと通常のシンボルを明確に区別する
- ネームスペース内やスコープ内における記述内容を正確に把握する
- 不要な「template」キーワードの使用を避ける
テンプレートとして定義されていないシンボルに誤って「template」を付加した場合、エラーが発生するため、記述前にシンボルの定義を再確認する習慣を持つことが大切です。
コード修正の具体例
以下のサンプルコードは、誤った記述を修正する具体例です。
最初に誤ったコードを示し、正しいコードを提示します。
・誤ったコード例
#include <iostream>
namespace N {
class Y {
// 通常のクラス定義
};
}
int main() {
// 「template」キーワードが不要な記述となっているためエラー発生
// N::template Y instance; // 誤った記述
std::cout << "誤った記述例" << std::endl;
return 0;
}
・正しいコード例
#include <iostream>
namespace N {
class Y {
// 通常のクラス定義
};
}
int main() {
// 「template」キーワードを外すことでエラーが解消される
N::Y instance;
std::cout << "正しい記述例:Y クラスのインスタンスが生成されました" << std::endl;
return 0;
}
上記のように、誤った記述から「template」キーワードを取り除くことで、エラーが解消されることが確認できます。
エラー解消確認の方法
コード修正後は、以下の手順でエラー解消を確認することができます。
- コンパイルオプションが正しく設定されているか確認する
- 修正後のコードをコンパイルし、C2903エラーが発生しないことを確認する
- サンプルコードを実行し、期待通りの出力が得られることをチェックする
例えば、先ほどの正しいコード例をコンパイルおよび実行することで、エラーが解消され、プログラムが正常に動作することが確認できます。
マネージコード環境でのC2903エラー
マネージコード環境、特にCLIや/generic/構文を使用する場合でも、C2903エラーは発生する可能性があります。
ここでは、generic構文を使用した際の注意事項について説明します。
generic構文での注意事項
マネージコード(/clrオプションを使用する環境)においても、テンプレートと同様に、genericキーワードを適切に使用する必要があります。
通常のクラスとgenericクラスを混在させる場合、記述ミスによりC2903エラーが発生するため、特に記述方法に注意する必要があります。
誤った記述例と正しい記述例
以下に、generic構文を使用した場合の誤った記述例と正しい記述例を示します。
・誤った記述例
#include <iostream>
namespace N {
// 通常のクラス定義
class Y {
// Y クラスの定義
};
// genericクラスの定義
generic <class T>
ref class Z {
// generic クラスの定義
};
}
int main() {
// 以下の記述は、Yはgenericではないためエラーとなる
// N::generic Y object; // 誤った記述例
std::cout << "generic キーワードの誤用例" << std::endl;
return 0;
}
・正しい記述例
#include <iostream>
namespace N {
// 通常のクラス定義
class Y {
// Y クラスの定義
};
// genericクラスの定義
generic <class T>
ref class Z {
// generic クラスの定義
};
}
int main() {
// genericキーワードの使用は、genericクラスに対してのみ行う
N::Z<int>^ instance = gcnew N::Z<int>();
std::cout << "正しい記述例:Z<int> のインスタンスが生成されました" << std::endl;
return 0;
}
この例では、通常のクラスであるY
に対してgenericキーワードが使用されず、genericクラスであるZ
にのみ正しくgenericキーワードが適用されています。
その結果、エラーC2903が発生しない正しい記述となっています。
まとめ
この記事では、C2903エラーが、テンプレートではないシンボルに「template」や「generic」キーワードを誤って付加した場合に発生するコンパイルエラーであると説明しています。
誤用例と正しい記述方法を具体例を交えながら解説し、コード修正の手順やエラー解消確認の方法、マネージコード環境での注意点についても触れています。