1

組み込みと同じユーザー定義型のキャストの処理を取得するにはどうすればよいですか。たとえば、次のようになります。

float a = 5.4;
std::string s = a;//error, no conversion avaible
int x = a;//warning, possible data loss
int y = (int)a;//fine
int z = static_cast<int>a;//fine
float b = c;//warning, possible data loss

ここで、独自の Int および Float クラスがあるとします。どうすれば同じエラーと警告が表示されるのでしょうか?

class Int
{
public:
    int value;
    Int(int v);
    ...
};
class Float
{
public:
    float value;
    Float(float v);
    ...
};
Int c = 10;
Float a = 5.5;
std::string s = a;
Int x = a;
Int y = (Int)a;
Int z = static_cast<Int>a;
Float b = c;

オーバーロードされたキャスト演算子を作成し、コンストラクターを使用することは知っていますが、暗黙的および明示的なキャストに対してこれを正しく機能させる方法がわかりません。これらのメソッド内に明示的なキャストを追加しないと、コンパイル時に警告が表示されますが、呼び出し時には警告が表示されません。追加した場合、クラスコード内でエラーは発生しませんが、それでもエラーは発生しませんどちらかを使用した場合の警告。

暗黙的にキャストしようとすると警告が生成されるように、キャスト演算子を明示的にマークする方法があると思いますが、明示的な (C スタイルまたは static_cast のいずれかの) キャストでは生成されません)。

編集:問題のすべての型が完全に既知である、このような場合には理解できると思いますが、一方または両方がテンプレートであり、どちらの型も組み込み型にマップされない場合はどうでしょうか?

template<typename T> class Vector2
{
public:
    T x, y;
    Vector2():x(0),y(0){}
    Vector2(T x, T y):x(x),y(y){}

    //Works as expected, warning if adding T and T2 is unsafe, or error if
    //incompatible*/
    template<typename T2>Vector2<T>& operator += (const Vector2<T2> &v);
    //Also works as desired
    Vector2<T>& operator *= (T s);

    //allows the conversion, but always generates warnings if 
    //T and T2 would, even if this constructor is used by an explicit
    //case. How can I suppress the warnings for the explicit cast, but
    //not for implicit casts?
    template<typename T2>Vector2(const Vector2<T2> &v);//uses implicit conversion form T2 to T
};

Vector2 から Vector2 への暗黙的なキャストは期待どおりに機能しますが、Vector2 から Vector2 へのキャストは、明示的な C スタイルまたは static_cast が使用された場合でも、常に (2、x に 1 つ、y に 1 つ) の警告を引き起こします。明示的なキャストではなく、暗黙的なキャストの警告を保持したい。

内部で各要素の明示的なキャストを使用する特別な T vector_cast(T2) 型メソッドを作成することで、これを回避できることはわかっていますが、むしろ C-Style と static_casts を使用できるようにしたいと思います

4

3 に答える 3

1

コンパイラが関与する型について持っている特別な知識に依存しており、コンパイラにこれらのことを教えることはできないため、あなたが望むことのいくつかは不可能です。

あなたが示したアイテムは、次のことを行う必要があります。

Float a = 5.5;

文句なしに動作するはずです。

std::string s = a;

POD フロートを使用する場合と必ずしも同じではないコンパイラ エラーが発生するはずですが、フロートには const char* 演算子がないため、それでも拒否されます。(もしそうなら、それを削除してこのエラーを引き起こします。)

Int x = a;

Float に "operator int()" がない限り、ここでデータ損失の可能性に関する警告が表示されるはずです。その場合、それを削除すると、コンパイラは強制的に「operator float()」を使用し、警告が発生します。

Int y = (int)a;

文句なしに動作するはずです。

Int z = static_cast<int>a;

これにより、前のものと同じ見かけの効果が得られるはずです。(それらの間には技術的な違いがありますが、この場合は問題になりません。)

Float b = c;

「c」が何であるかを示していないため、これが何をするかはわかりません。

于 2009-10-06T22:03:31.633 に答える
1

私も仕方がないと思います。私が達成できる最善の方法は、警告を生成したい行がまったくコンパイルされないようにすることです。

class Int
{
public:
    int value;
    Int(int v);
};

class Float
{
public:
    float value;
    Float(float v);
    operator int() { return static_cast<int>(value); }
};

int main()
{
    Float a = 5.5;
    //Int x = a; //no warning, simply doesn't compile
    Int y = (int)a;
    Int z = static_cast<int>(a);
}

編集:Vector2に関する質問について

行うべきことの 1 つは、異なる Vector2 型間のすべての暗黙的な変換を無効にすることです。ショートカットとして、vector_cast明示的な変換を許可する を指定できます。

template <class T, class S>
Vector2<T> vector_cast(const Vector2<S>& s)
{
    return Vector2<T>(static_cast<T>(s.x), static_cast<T>(s.y));
}

もう 1 つの方法は、安全な変換のために変換コンストラクターを有効にするために、いくつかのテンプレート メタプログラミングを導入することです。

boost にはそのような が含まれていないように思われるtype_traitので、自分でロールしました。

これはいくらか単純化されています。Target は少なくとも Source と同じ大きさでなければならず、Source が浮動小数点の場合、Target は整数であってはなりません。ただし、符号の問題と、浮動小数点型が整数型の全範囲を表すことができるかどうかという問題は無視されます (たとえば、float はすべての 32 ビット int を正確に格納できませんが、double は格納できます)。

#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>

template <class S, class T>
struct is_safe_conversion:
    boost::integral_constant<
        bool,
        (sizeof(S) <= sizeof(T)) && !(boost::is_floating_point<S>::value && boost::is_integral<T>::value)
    >
{
};

template<typename T> class Vector2
{
public:
    T x, y;
    Vector2():x(0),y(0){}
    Vector2(T x, T y):x(x),y(y){}

    template <class U>
    Vector2(const Vector2<U>& other, typename boost::enable_if<is_safe_conversion<U, T> >::type* = 0):
        x(other.x), y(other.y) {}

};

template <class T, class S>
Vector2<T> vector_cast(const Vector2<S>& s)
{
    return Vector2<T>(static_cast<T>(s.x), static_cast<T>(s.y));
}

int main()
{
    Vector2<double> vd, vd2;
    Vector2<int> vi, vi2;
    Vector2<float> vf, vf2;

    vd = vd2;
    vd = vi;
    vd = vf;

    //vi = vd; //error
    vi = vector_cast<int>(vd);
    vi = vi2;
    //vi = vf; //error
    vi = vector_cast<int>(vf); //explicit

    //vf = vd; //error
    vf = vector_cast<float>(vd);

    //following compiles, but produces a warning (float cannot represent all integers) 
    //TODO: enhance is_safe_conversion!
    vf = vi; 
    vf = vf2;
}
于 2009-10-06T22:06:54.363 に答える
0

キャストに対して独自のコンパイラ警告を作成する方法はないと思います。

于 2009-10-06T21:55:27.810 に答える