在下面的C ++ 0x代码中,我尝试使用a来克隆对象 克隆成员函数(如果存在)并回退到副本上 构造:
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 ...-&gt; decltype(expr)来清除错误的形式 表达式作为模板参数推导(SFINAE)的一部分和 解决两个克隆功能模板之间可能存在的歧义 部分订购w.r.t.第二个函数参数。
不幸的是,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*
,则代码会因为重载解析而在此情况下更喜欢第一个函数模板。但这违背了将表达式作为函数声明的一部分的目的。目的是使编译器在出现错误时将该函数踢出重载决策集。
答案 0 :(得分:1)
我遇到了与MSVC非常相似的问题,结果发现编译器无法识别虚函数中的共变量返回类型。尝试将derived
的克隆定义更改为返回abc
。
答案 1 :(得分:1)
我想我确信这实际上是一个编译器错误并提交了report。让我们看看发生了什么。解决方法decltype(new T(*ptr))
可以替换为T*
。唯一的区别是函数模板将保留重载决策集的一部分,在这种情况下这不是一个大问题。
编辑:顺便说一句,我被告知clang ++接受上述代码。