形成错误的C++ 0x代码或编译器错误?

sel*_*tze 6 c++ gcc sfinae c++11

在下面的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;
}
Run Code Online (Sandbox Code Playgroud)

我们的想法是使用auto ...-> decltype(expr)来清除不正确的表达式,作为模板参数推导(SFINAE)的一部分,并通过部分排序和第二个函数解决两个克隆函数模板之间可能存在的歧义参数.

不幸的是,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
Run Code Online (Sandbox Code Playgroud)

现在,问题是,这是一个编译器错误还是我错误地认为SFINAE适用于此?我会以一个坚实的推理来回答这个问题.

编辑: 如果由于重载决议而decltype(new T(*ptr))改为T*代码编译,在这种情况下更喜欢第一个函数模板.但这违背了将表达式作为函数声明的一部分的目的.目的是使编译器在出现错误时将功能从超载分辨率集中取出.

sel*_*tze 1

我想我说服了自己这实际上是一个编译器错误并提交了报告。让我们看看发生了什么。作为解决方法,decltype(new T(*ptr))可以替换为T*. 唯一的区别是函数模板将保留为重载解析集的一部分,在这种情况下这不是一个大问题。

编辑:顺便说一句,我被告知 clang++ 接受上述代码。