これは私の前の質問に対する一種のフォローアップ質問です(メンバー関数、フリー関数、および演算子の存在をチェックするための統一された方法)。
私はのための演算子を生成しようとしていますscalar * vector
し、vector * scalar
それらが手元にベクトルクラスによって提供されていない場合にのみ。これらの演算子が次のように存在するかどうかを確認します。
template<typename C, typename Ret, typename Arg>
struct has_operator_mult {
private:
template<typename L, typename R, std::enable_if_t<
std::is_convertible
<
decltype(std::declval<L>() * std::declval<R>()),
Ret
>::value
> * = nullptr >
static constexpr std::true_type check(nullptr_t);
template<typename, typename>
static constexpr std::false_type check(...);
public:
typedef decltype(check<C, Arg>(nullptr)) type;
static constexpr bool value = type::value;
};
Eigenライブラリ(バージョン3.3.4)のベクトルの場合、これにより次のようになります。
has_operator_mult<Vector3f, Vector3f, float>::value; // true -> Vector3f = Vector3f * float
has_operator_mult<float, Vector3f, Vector3f>::value; // true -> Vector3f = float * Vector3f
has_operator_mult<Vector3f, Vector3f, std::vector<float>>::value // false
大丈夫です。ただし、右側の乗算演算子を宣言しようとするとすぐに、次のようになります。
template<typename TVector3D,
std::enable_if_t
<
!has_operator_mult<TVector3D, TVector3D, float>::value
> * = nullptr
>
TVector3D operator*(const TVector3D & lhs, float rhs)
{
return TVector3D{}; // implementation does not matter here
}
出力がに変わります
has_operator_mult<Vector3f, Vector3f, float>::value; // true -> Vector3f = Vector3f * float
has_operator_mult<float, Vector3f, Vector3f>::value; // false -> Vector3f = float * Vector3f
ですから、私が自分自身を宣言していないというオペレーターは、私の存在チェックに従ってなんとか消えてしまいます。興味深いことに、これは私が使用するかどうかは変わりません
std::enable_if_t
<
!has_operator_mult<TVector3D, TVector3D, float>::value // with negation
>
または
std::enable_if_t
<
has_operator_mult<TVector3D, TVector3D, float>::value // without negation
>
ただし、どちらの演算子も引き続き呼び出すことができますが、Eigenライブラリの実装を呼び出します。
Vector3f v(1, 2, 3);
std::cout << v * 5.f << std::endl << std::endl;
std::cout << 5.f * v << std::endl << std::endl;
他の乗算演算子を追加すると、さらに混乱します。
template<typename TVector3D,
std::enable_if_t
<
!has_operator_mult<float, TVector3D, TVector3D>::value
> * = nullptr
>
TVector3D operator*(float lhs, const TVector3D & rhs)
{
return TVector3D{};
}
has_operator_mult<Vector3f, Vector3f, float>::value; // false -> Vector3f = Vector3f * float
has_operator_mult<float, Vector3f, Vector3f>::value; // true -> Vector3f = float * Vector3f
Vector3f v(1, 2, 3);
std::cout << v * 5.f << std::endl << std::endl; // calls my implementation
std::cout << 5.f * v << std::endl << std::endl; // calls Eigen implementation
std::cout << v * 5 << std::endl << std::endl; // compiler error, ambiguous function call
std::cout << 5 * v << std::endl << std::endl; // calls Eigen implementation
なんでこんなことが起こっているの?演算子の存在のチェックは間違っていますか?自分でオペレーターを宣言しない限り、うまくいくようです。
gccとclangを使用すると、コードスニペットは正常に機能しますが、MSVCでは機能しません。したがって、問題をMSVCチームに報告することをお勧めします。
そこにある3つのコンパイラを使って自分で試すことができます。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加