0

データメンバーのみを持つCFixedLengthStringクラステンプレートがあります。データメンバーのサイズは、テンプレートタイプの引数によって決定されます。

template<size_t _Length>
class CFixedLengthString
{
private:
   char Buffer[_Length];

public:
   // Has constructors, conversion operators etc. 
   // Listing the important ones 
   operator const char*();
   operator = (const CFixedLengthString&);
   operator = (const char*);
};

自動変換は便利です。例:

CFixedLengthString<10> buf;
buf = "SomeString";

strlen(buf);

しかし、この便利さにより、次のことが成功することもできます。

CFixedLengthString<10> buf1;
CFixedLengthString<20> buf2;
buf1 = buf2;

ここでbuf2const char*、暗黙の変換演算子を介して変換され、operator=で呼び出されconst char*ます。したがって、<20>に変換され<10>ます。

ここで重要なもの。CFixedLengthStringこのために、サイズの異なる 代入演算子を作成しました。

template<size_t _TOtherSize>
void operator=(const CFixedLengthString<_TOtherSize>&);

そしてもちろん、それをプライベート<20>にしたので、に変換するとコンパイラエラーが発生し<non-20>ます。しかし、驚いたことに、コンパイラは文句を言いません!このプライベートオペレーターを呼び出すことができます!

<N>にコピーされている場合は<N>、通常の割り当て操作者を呼び出します。<N>コンパイラにコピー(割り当て)されている場合は、<M>この特殊な演算子を呼び出します。

しかし、なぜコンパイラはこのシナリオでプライベート(および保護された)の呼び出しを許可するのですか?VC2008コンパイラを使用しています。私はこのコンパイラの解決策だけを探しています。

今のところ、この特殊な関数の本体内に静的アサーションを記述しました(このような誤った変換を禁止するため)。

編集: すべての応答は感謝しています。私の唯一の質問は:

  • privateなぜ私がエリアに置いた特殊バージョンが呼び出せるのですか?

私たちは皆delete、防御プログラミングのためにプライベート、宣言のみの関数、属性、およびその他の側面を使用します。私は同じことをしようとしています。しかし、コンパイラはプライベート関数を呼び出すことができます!

編集2: サンプルコード:

template<size_t SIZE>
class FixedString
{
public:
    operator const char*();
    void operator =(const char*);

    void operator =(const FixedString&);

    // Disallow
private:
    template<size_t OTHERSIZE>
    void operator=(const FixedString<OTHERSIZE>&);
};

int main()
{
    FixedString<10> buf1;
    FixedString<20> buf2;

    buf2 = buf1;   // NO ERROR!!
}

の特殊バージョンを削除しoperator=ても、引き続き機能します。そして、私はそれを避けたいです!

4

2 に答える 2

1

あなたの場合、c_str()を介してchar*に変換するためのstd::stringと同様のソリューションであるoperator const char*()ようなアクセサ関数を優先して削除することができます。c_ptr()

別の解決策は、代わりに割り当てをoperator = (const char*);プライベートにし、 char *から明示的なコンストラクターを定義して、必要な場合にのみ型間で明示的に変換できるようにすることです。

class CFixedLengthString
{
public:
     explicit CFixedLengthString( char* str ) { *this = str );
private:
     operator = (const char*);
};

...
CFixedLengthString<10> buf1;
CFixedLengthString<20> buf2;
buf1 = CFixedLengthString<10>(buf2);

この現在の例では、次のように制限されます。

CFixedLengthString<10> buf1( "string" );
buf1 =  CFixedLengthString<10>("string");
于 2013-02-27T09:17:25.097 に答える
0

これを達成する方法はいくつかあります。

  1. あなたoperator const char*はいくつかの場所で便利かもしれません、しかし明らかにあなたがそれを望まないいくつかの場所でそれは引き起こされます。削除するか、類似の関数に置き換えるstd::string::c_str()か、作成することを検討してくださいexplicit(C ++ 11のみ)。
  2. プライベート(C ++ 03)または削除された(C ++ 11のみ)ために機能しない他のタイプの変換コンストラクターを明示的に宣言できます。

    template <class T> 
    CFixedLengthString& operator=(T const&) = delete;
    
    //or delete just other FixedLengthStrings:
    template <size_t L> // _Length is a reserved identifier, do't use it!
    CFixedLengthString& operator=(CFixedLengthString<L> const&) = delete;
    

VSはプライベート演算子を尊重しないため(既知のバグ)、演算子privateの宣言はVS2012より前のVisual Studioでは機能しません:http: //connect.microsoft.com/VisualStudio/feedback/details/649496/visual-c-doesnt-オペレーターメンバー関数テンプレートのaccess-modifier-respect- それにもかかわらず、これらのオペレーターに実装がない場合、リンカーは文句を言います(そうすべきではありません)。

于 2013-02-27T10:50:52.300 に答える