これはVS2010(with Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
)で再現できますが、これはバグだと思います。正直なところ、ここに含まれるスコープの問題に頭を悩ませることは困難ですが、それは目前の問題とは関係がないようです(ベーステンプレートとスペシャライゼーションが一緒にネストされており、VSが再帰レベルについて不平を言っているため) 、未定義のシンボルではありません)。いずれにせよ、それは非常に興味深い例です。VS 2005(with Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86
)でも同じ動作が見られます。MicrosoftがVS2010のバグレポートをまだ受け入れていないようです(Microsoft ConnectVisualStudioページとフィードバックフォームから判断して)。問題がまだ修正されていない場合は、VS 2012にアクセスできる誰かが元のコードをテストし、バグレポートを提出できることを願っています(おそらく、以前にMicrosoftの注意を引いたという兆候は見られません)。
この問題を回避するには、再帰の原因となっているクラステンプレートを前方宣言します。
// Forward declaration of problematic inherited class template
template<template<int> class A, int n = 0, typename obj_type = typename A<n>::type>
struct Instantiate;
template<template<int> class A, int n>
struct Instantiate<A,n,void>
{
};
// Now compiles!
template<typename O>
struct test
{
template<int n, bool=true> struct array { typedef void type; };
template<int n> struct array2 { typedef typename array<n>::type type; };
template<bool u> struct array<0,u> { typedef int type; };
template<bool u> struct array<1,u> { typedef float type; };
template<bool u> struct array<2,u> { typedef bool type; };
Instantiate<array2> objects;
};
// Instantiate each type of a type array (which is a template<int>)
// void is taken as the end of the array
template<template<int> class A, int n, typename obj_type>
struct Instantiate : public Instantiate<A,n+1>
{
obj_type object;
Instantiate() : object() {}
};
int main()
{
test<int> obj;
return 0;
}
編集
Synxis、rise4funリンクに感謝します。これは、後で役立つはずです。驚くべきことに、元のコードはで正常に機能しますがVS2012 CTP
、それでも壊れていVS2012 RTM
ます。http://rise4fun.com/Vcpp/aRhを参照してください。CTP
の代わりにデフォルトのオプションRTM
が私を超えているのはなぜですか。この例は間違いなく奇妙なものです。
Instantiate
によって使用されるライブラリヘッダー以外に何かありますtest
か?そうでない場合、ユーザーはInstantiate
テンプレート定義を明示的に前方宣言してtest
から、ヘッダーを含めることができます。それ以外の場合は、必要な他のものとともに前方宣言を含むヘッダーファイルを作成できます。ほとんどの場合、この問題の影響を受けるユーザー向けに特別な回避策ヘッダーを作成することをお勧めします。これは確かに物事を非常に厄介でエラーが発生しやすくします(主にデフォルトのテンプレート引数が原因です)が、それは機能します:
myLib_workaround_forward_declaration.hpp:
#ifndef MYLIB_WORKAROUND_FORWARD_DECLARATION // or #pragma once if supported
#define MYLIB_WORKAROUND_FORWARD_DECLARATION
// amount of error checking is up to you
// eg, are workaround header files mixed with the regular ones
// or included in the wrong order
template<template<int> class A, int n = 0, typename obj_type = typename A<n>::type>
struct Instantiate;
#endif
myLib_workaround_implementation.hpp:
#ifndef MYLIB_WORKAROUND_IMPLEMENTATION // or #pragma once if supported
#define MYLIB_WORKAROUND_IMPLEMENTATION
// amount of error checking is up to you
// eg, are workaround header files mixed with the regular ones
// or included in the wrong order
template<template<int> class A, int n, typename obj_type>
struct Instantiate : public Instantiate<A,n+1>
{
obj_type object;
Instantiate() : object() {}
};
template<template<int> class A, int n>
struct Instantiate<A,n,void>
{
};
#endif
userFile.cpp:
// Forward declaration of problematic inherited class template
#include "myLib_workaround_forward_declaration.hpp"
// Now compiles!
template<typename O>
struct test
{
template<int n, bool=true> struct array { typedef void type; };
template<int n> struct array2 { typedef typename array<n>::type type; };
template<bool u> struct array<0,u> { typedef int type; };
template<bool u> struct array<1,u> { typedef float type; };
template<bool u> struct array<2,u> { typedef bool type; };
Instantiate<array2> objects;
};
#include "myLib_workaround_implementation.hpp"
int main()
{
test<int> obj;
return 0;
}