質問

なんだかランダムな質問ですが…

私が探しているのは、キャスト元のクラス インスタンスの定義された演算子を使用するキャスト操作を表現する方法であり、その型に定義されたキャスト演算子がない場合はコンパイル時エラーを生成します。したがって、たとえば、私が探しているものは次のようなものです。

template< typename RESULT_TYPE, typename INPUT_TYPE >
RESULT_TYPE operator_cast( const INPUT_TYPE& tValue )
{
    return tValue.operator RESULT_TYPE();
}

// Should work...
CString sString;
LPCTSTR pcszString = operator_cast< LPCTSTR >( sString );

// Should fail...
int iValue = 42;
DWORD dwValue = operator_cast< DWORD >( iValue );

興味深い補足:上記のコードは、VS2005 C++ コンパイラをクラッシュさせ、コンパイラのバグと思われるため、VS2008 C++ コンパイラでは正しくコンパイルされませんが、アイデアを示すことができれば幸いです。

この効果を達成する方法を知っている人はいますか?

編集:これを使用する理由を説明するためのさらなる理論的根拠。型をカプセル化または抽象化するラッパー クラスがあり、それをカプセル化された型にキャストしているとします。static_cast<> を使用することもできますが、失敗させたい場合には機能する可能性があります (例:演算子が存在しないために失敗したい場合、コンパイラは、要求した型への変換を許可する演算子を選択します)。

確かにこれは珍しいケースですが、カプセル化された関数でコンパイラに実行してもらいたいことを正確に表現できないのは面倒です...したがって、ここでの質問です。

役に立ちましたか?

解決

あなたが投稿したコードは、 Cameau コンパイラ (これは通常、それが有効な C++ であることを示す良い指標です)。

ご存知のとおり、有効なキャストは 1 つだけのユーザー定義キャストで構成されます。そのため、私が考えていた解決策は、キャスト テンプレートに新しい型を定義して、別のユーザー定義キャストを追加することでした。 静的アサート 新しい型から結果の型へのキャストは利用できないこと (を使用) ブーストはコンバーチブルです)、ただし、これはキャスト演算子とキャストコンストラクター(1つの引数を持つctor)を区別せず、追加のキャストを実行できるようにします(例: void*bool)。キャスト演算子とキャストコンストラクターを区別することが重要であるかどうかはわかりません。 正しい やるべきことですが、それが質問に記載されていることです。

数日考えた結果、キャスト オペレーターのアドレスを取得するだけでよいことに気づきました。C++ のメンバー構文へのポインターの複雑さのため、これは言うは易く行うは難しです (正しく理解するのに予想よりもずっと時間がかかりました)。これが VS2008 で動作するかどうかはわかりません。Cameau でのみ確認しました。

template< typename Res, typename T>
Res operator_cast( const T& t )
{
    typedef Res (T::*cast_op_t)() const;
    cast_op_t cast_op = &T::operator Res;
    return (t.*cast_op)();
}

編集: VS2005とVS2008でテストする機会がありました。私の発見は元の投稿者のものとは異なります。

  • VS2008 では、元のバージョンは正常に動作するようです (私のバージョンも同様です)。
  • VS2005 では、元のバージョンは、組み込み型 (例:int を int にキャストする) コンパイル エラーが発生した後、これは私にとってもそれほど悪いことではないようで、私のバージョンはすべてのケースで動作するようです。

他のヒント

明示的とマークされた変換コンストラクターを使用する方法暗黙的に変換された型がラッパークラスを初期化することをコンパイラが許可しないようにします。

通常、テンプレート関連のコンパイラエラーメッセージは解明するのが非常に苦痛なので、各変換を指定することを気にしない場合は、デフォルトのテンプレート定義を提供することで、失敗した場合により有益なメッセージをコンパイラに送信させることができます。これは、コンパイラが実際に呼び出されるテンプレート内のコードのみをコンパイルしようとするという事実を使用しています。

#include <string>

// Class to trigger compiler warning   
class NO_OPERATOR_CONVERSION_AVAILABLE
{
private:
   NO_OPERATOR_CONVERSION_AVAILABLE(){};
};

// Default template definition to cause compiler error
template<typename T1, typename T2> T1 operator_cast(const T2&)
{
   NO_OPERATOR_CONVERSION_AVAILABLE a;
   return T1();
}

// Template specialisation
template<> std::string operator_cast(const std::string &x)
{
   return x;
}

テンプレートの特殊化が必要なように聞こえますが、次のようになります。

/* general template */
template<typename T1, typename T2> T1 operator_cast(const T2 &x);

/* do this for each valid cast */
template<> LPCTSTR operator_cast(const CString &x) { return (LPCTSTR)x; }

編集:別の投稿で述べたように、サポートされていないキャストが実行された場合、一般的なバージョンに何かを入れて、より有用なエラーメッセージを提供できます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top