C++で特定のクラスを利用すると、稀に以下のようなエラーが発生する。
// Implicit instantiation of undefined template 'std::__1::array<int, 3>'
std::array<int, 3> ary;
原因
ヘッダーファイルがインポートされていないことが原因。クラスに対応するヘッダーをきちんとインポートすれば良い。
#include <array>
std::array<int, 3> ary; // OK
根本原因
クラスの定義が見つからないことが原因。
// error: implicit instantiation of undefined template 'std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >'
std::stringstream ss{};
std::stringstream
クラスなどはiosfwd
ヘッダファイル側でtypedefによる前方宣言がされているが、実際の実装はsstream
ヘッダで定義されているので、そちらをインクルードする必要がある。
/* iosfwd.h */
typedef basic_stringstream<char> stringstream;
/* sstream.h */
template <class Char, class Traits, class Allocator>
class basic_stringstream : public basic_iostream<Char, Traits> {}
iosfwd内の前方宣言は主にヘッダーファイル側で利用することが想定されている。前方宣言のみをインクルードしたほうがコンパイル速度が早くなるためだ。sstreamやiostreams等の詳細なヘッダーファイルは、実装ファイル側でインクルードすればいい。逆にヘッダーファイル側で詳細なヘッダーファイルを読み込んでしまうと、それらのヘッダーファイル側に含まれる実装コードも余計にコンパイルされてしまうため、コンパイル速度の低下に繋がる。
同じようにstd::array
クラスで以下のような、
No member named 'array' in namespace 'std'
というエラーにならないのは、array
クラスが前方宣言されているため(標準ライブラリ側で暗黙的に前方宣言されている場合がある)。
実際にMyArray
というクラスを前方宣言のみ行い、実体は未定義の状態でコンパイルしてみると、今回と同様のエラーが発生する。
// 前方宣言
template <class _Tp, size_t _Size> struct MyArray;
// 定義省略
// template <class _Tp, size_t _Size> struct MyArray {};
/// Implicit instantiation of undefined template 'MyArray<int, 3>'
MyArray<int, 3> ary;