Visual Studioで興味深い、しかし非常に厄介なバグに遭遇しました。以下は最も単純な再現です:(コメントを外すとVSがコードをビルドできるようになります)
#include <iostream>
using namespace std;
//#define BUILD_ON_VS
class CC
{
public:
template<typename T>
struct Foo
{
template<T foo>
void bar()
{
cout << "VC likes this!\n";
}
#ifndef BUILD_ON_VS
template<T foo>
void bar1();
#endif
};
Foo<int> m_foo;
};
#ifndef BUILD_ON_VS
template<typename T>
template<T foo>
void CC::Foo<T>::bar1()
{
cout << "VC doesn't like this...\n";
}
#endif
int main()
{
CC cc;
cc.m_foo.bar<-1>();
#ifndef BUILD_ON_VS
cc.m_foo.bar1<2>();
#endif
return 0;
}
基本的に、VisualStudioのクラスの外に関数バーの定義を配置することはできません。それ以外の点では、barとbar1はまったく同じです。VS2010とVS2012でテストしましたが、どちらもエラーで失敗しました。
error C2244: 'CC::Foo<T>::bar1' : unable to match function definition to an existing declaration
definition
'void CC::Foo<T>::bar1(void)'
existing declarations
'void CC::Foo<T>::bar1(void
ただし、compileonlineやideoneなどのすべてのオンラインコンパイラで動作します。
コードベースをクリーンに保つために、.hではなくcppファイル内にすべてを保持したいと思います。
Setting var1 to:
{
template<typename TT, TT foo>
void bar1();
}
template<typename T>
template<typename TT, TT foo>
void CC::Foo<T>::bar1()
{
}
これも機能しますが、同じテンプレートパラメータを再定義することでコードがばかげているように見え、バグが発生しやすくなります。また、インターフェイスが乱雑になります。