6

次の C++0x コードでは、クローン メンバー関数 (存在する場合) を使用してオブジェクトのクローンを作成し、コピー コンストラクターにフォールバックしようとしました。

struct use_copy_ctor {};
struct prefer_clone_func : use_copy_ctor {};

template<class T>
auto clone(T const* ptr, prefer_clone_func)
-> decltype(ptr->clone())
{ return ptr->clone(); }

template<class T>
auto clone(T const* ptr, use_copy_ctor)
-> decltype(new T(*ptr))
{ return new T(*ptr); }

struct abc {
  virtual ~abc() {}
  virtual abc* clone() const =0;
};

struct derived : abc
{
  derived* clone() const { return new derived(*this); }
};

int main()
{
  derived d;
  abc* p = &d;
  abc* q = clone(p,prefer_clone_func());
  delete q;
}

アイデアは、 auto...->decltype(expr) を使用して、テンプレート引数推定 (SFINAE) の一部として不適切な形式の式を除外し、2 番目の関数に関して部分的な順序付けを介して、両方のクローン関数テンプレート間の可能なあいまいさを解決することです。パラメータ。

残念ながら、GCC 4.5.1 はこのプログラムを受け入れません:

test.cpp: In function 'int main()':
test.cpp:28:39: error: cannot allocate an object of abstract type
  'abc'
test.cpp:14:12: note:   because the following virtual functions are
  pure within 'abc':
test.cpp:16:16: note:        virtual abc* abc::clone() const
test.cpp:28:39: error: cannot allocate an object of abstract type
  'abc'
test.cpp:14:12: note:   since type 'abc' has pure virtual functions

さて、問題は、これはコンパイラのバグなのか、それとも SFINAE がここに適用されると仮定するのは間違っていたのかということです。根拠のある回答をいただければ幸いです。

編集:この場合、最初の関数テンプレートを優先するオーバーロードの解決のために、コード に変更decltype(new T(*ptr))するとコンパイルされます。T*しかし、これは式を関数宣言の一部として持つ目的に反します。目的は、エラーが発生した場合に、オーバーロード解決セットからコンパイラーが関数を追い出すようにすることです。

4

2 に答える 2

1

私はMSVCで非常によく似た問題を抱えていましたが、コンパイラーが仮想関数で共変の戻り型を認識しないことが判明しました。derivedクローンの定義を変更して、を返すようにしてabcください。

于 2011-01-28T11:30:58.040 に答える
1

これは実際にはコンパイラのバグであると確信し、レポートを提出したと思います。しばらく様子を見てみましょう。回避策として、decltype(new T(*ptr))に置き換えることができますT*。唯一の違いは、関数テンプレートがオーバーロード解決セットの一部のままであることです。これは、この場合大きな問題ではありません。

編集:ところで、clang ++は上記のコードを受け入れると言われました。

于 2011-01-28T12:58:12.077 に答える