元のコード
以下はVisualC++ Express 2010でコンパイルされますが、間違った答えが生成されます。
#include <iostream>
template <typename X>
struct point
{
template <typename Seq>
struct point_iterator
{
template <typename>
struct deref
{
static const int value = 0;
};
template <typename Sq>
struct deref< point_iterator<Sq> >
{
static const int value = 1;
};
};
};
int main()
{
typedef point<int> point_t;
typedef point_t::point_iterator<point_t> Iterator;
int v = Iterator::deref<Iterator>::value;
std::cout << v << "\n"; // prints 1 on gcc 4.5.1, prints 0 on VC++ 2010
return 0;
}
これはあなたが得たコンパイルエラーを説明しています:VC++はderef
あなたが定義しなかったプライマリテンプレートをインスタンス化しようとしました。この時点で、VC ++にエラーがあり、gcc/clangが優れたコンパイラであるように見える場合があります。
中間の「解決策」
ただし、point_iterator
とそのネストさderef
れた名前空間を外部の名前空間に移動すると、 detail
gccとVC++の両方で同じですが間違った結果になります。呼び出すdetail::point_iterator::deref
と必要なものが得られますが、ネストされたpoint_iterator
内部を呼び出すとpoint
、gccとVC++の両方で間違った結果が得られるようになりました。したがって、ネストされたテンプレートは、一般的にコンパイラでは難しいようです。
#include <iostream>
namespace detail {
template <typename Seq>
struct point_iterator
{
template <typename>
struct deref
{
static const int value = 0;
};
template <typename Sq>
struct deref< point_iterator<Sq> >
{
static const int value = 1;
};
};
}
template<typename X>
struct point
{
template<typename Seq>
struct point_iterator
:
public detail::point_iterator<Seq>
{};
};
int main()
{
typedef point<int> point_t;
typedef point_t::point_iterator<point_t> Iterator1;
int v1 = Iterator1::deref<Iterator1>::value;
std::cout << v1 << "\n"; // prints 0 on both gcc 4.5.1 and VC++ 2010
typedef detail::point_iterator<point_t> Iterator2;
int v2 = Iterator2::deref<Iterator2>::value;
std::cout << v2 << "\n"; // prints 1 on both gcc 4.5.1 and VC++ 2010
return 0;
}
推奨されるアプローチ
ネストされたテンプレートには他にも問題があります。外部テンプレートも特殊化せずに内部テンプレートを明示的に特殊化することはできません(皮肉なことに、VC ++ではこの非標準機能を使用できます!)。これは、ダミーのテンプレートパラメータを使用し、それらを部分的に特殊化することで解決できます(ただし、このダミーのテンプレートパラメータにデフォルト値を指定すると、VC ++では偽のコンパイラ警告を抑制する必要があります)。
したがって、取得したネストされたテンプレート階層全体を解きほぐし、3つの個別のテンプレートを定義して、好みに合わせて特殊化することをお勧めします。これにより、最も簡単なコードが生成され、驚くことはありません。
#include <iostream>
template<typename X>
struct point {};
template <typename Seq>
struct point_iterator {};
template <typename>
struct deref
{
static const int value = 0;
};
template <typename Sq>
struct deref< point_iterator<Sq> >
{
static const int value = 1;
};
int main()
{
typedef point<int> point_t;
typedef point_iterator<point_t> Iterator1;
int v = deref<Iterator1>::value;
std::cout << v << "\n"; // prints 1 on both gcc 4.5.1 and VC++ 2010
return 0;
}