VisualStudioではC++0xの拡張機能がいくつかあり、それら及び
テンプレートを使って、ベクトルのクラスをカスタマイズしているのですが
半日以上デバッグしても以下のような、ほんの数行のプログラムのコンパイルを通すことができません。
動機は以下のようなものですやりたいこと:
ベクトルの内積、および定数倍の実装を行う。
しかし戻り値の型は 二つの引数の型によって決まるようにしたい。
► スポイラーを表示
(必要のない部分は大幅に端折ってあります)
#include<type_traits>
//空のクラステンプレートパラメータ用
struct Empty{};
namespace Linear{
namespace Private{
//掛け算の戻り値の型からconstを外す
template <typename LHS, typename RHS >
struct RCMul{
typedef typename std::remove_const< decltype( LHS(0) * RHS(0) ) >::type type;
//typedef Empty type;
};
//掛け算の戻り値の型を得る
template <typename LHS, typename RHS >
struct CMul{
typedef decltype( LHS(0) * RHS(0) ) type;
};
}
template<typename NType>
struct Vector{
public:
NType x;
NType y;
NType z;
Vector():x(0),y(0),z(0){}
template <typename OtherType>
Vector( OtherType init_x, OtherType init_y, OtherType init_z )
:x(init_x), y(init_y), z(init_z){
}
template <typename OtherType>
Vector( const Vector<OtherType>& other )
:x(other.x), y(other.y), z(other.z){
}
template <typename OtherType>
Vector& operator=( const Vector<OtherType>& other ){
x=other.x;
y=other.y;
z=other.z;
return *this;
}
};
//内積
template < typename NType1, typename NType2 >
typename Private::CMul< NType1, NType2 >::type
operator* ( const Vector<NType1>& lhs, const Vector<NType2>& rhs ){
return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z;
}
//スカラーとの掛け算
template <typename NType1, typename NType2>
const Vector< typename Private::RCMul< NType1, NType2 >::type >
operator*( const Vector<NType1>& v, NType2 s ){
return Vector< typename Private::RCMul< NType1, NType2 >::type >(v.x*s, v.y*s, v.z*s);
}
template < typename NType1, typename NType2 >
const Vector< typename Private::RCMul< NType1, NType2 >::type >
operator*( NType1 s, const Vector<NType2>& v ){
return Vector< typename Private::RCMul< NType1, NType2 >::type >(s*v.x, s*v.y, s*v.z);
}
}
using namespace Linear;
int main(){
Vector<double> v(1.0, 1.0, 0.0 );
Vector<double> u = v;
double d = v*u;
}
なぜでしょうか?
環境はVisual Studio 2010ですが、
エラーを確認してみると
error C2440: '<function-style-cast>' : 'int' から 'Linear::Vector<NType>' に変換できません。
1> with
1> [
1> NType=double
1> ]
1> コンストラクターはソース型を持てません、またはコンストラクターのオーバーロードの解決があいまいです。
1> main.cpp(81) : コンパイルされたクラスの テンプレート のインスタンス化 'Linear::Private::RCMul<LHS,RHS>' の参照を確認してください
1> with
1> [
1> LHS=Linear::Vector<double>,
1> RHS=double
1> ]
と出ます。
RCMulのインスタンス化がおこなわれているとのことですが、この場合よりマッチするのは
operator*(const Vector<NType1>& lhs, const Vector<NType2>& rhs)だと思うのです。
実際上記の
typedef typename std::remove_const< decltype( LHS(0) * RHS(0) ) >::type type;
//typedef Empty type;
のコメントアウトを変更し
//typedef typename std::remove_const< decltype( LHS(0) * RHS(0) ) >::type type;
typedef Empty type;
とすればコンパイルは問題なく通ります。
decltypeを使用することによってコンパイルが通らなくなるということだろうという結論には至りましたが、
これはどういう理由なのでしょうか? というのが質問です。
またよい解決法をご存知であればそちらも教えていただきたく思います。
よろしくお願いします。