我试图设计一个不可复制的对象,并阻止编译器考虑该类上隐式声明的复制构造函数.这是我正在开发的单元测试夹具.
考虑到我有两个主要对象:核心库对象,Root和派生的特殊对象被测试,Branch.我正试图开发一个测试夹具类,Fixture处理细节的设置&与核心Root对象交谈.所以这是我迄今为止所建立的简单说明:
(Here is an ideone link与以下相同的代码,除了我已经定义了我自己的非复制)
#include <boost/utility.hpp> #include <boost/noncopyable.hpp> class Root { }; class Fixture : public boost::noncopyable { public: Fixture (Root& root) : mRoot (root) { } private: Root& mRoot; }; class Branch : public Root,public Fixture { public: Branch() : Fixture (*this) { } }; int main() { Branch branch; }
编译结果如下:
main.cpp: In constructor ‘Branch::Branch()’: main.cpp:30:23: error: call of overloaded ‘Fixture(Branch&)’ is ambiguous main.cpp:30:23: note: candidates are: main.cpp:13:5: note: Fixture::Fixture(Root&) main.cpp:8:7: note: Fixture::Fixture(const Fixture&)
为了防止C 03编译器隐含地声明Fixture的复制构造函数是不可能的,除非我自己声明至少一个.但即使是:
class Fixture : public boost::noncopyable { public: Fixture (Root& root) : mRoot (root) { } private: Fixture (const Fixture&); Fixture (Fixture&); Root& mRoot; };
…在Branch的初始化列表中初始化Fixture时,编译器仍然会考虑这些私有声明:
Fixture (*this)
我希望编译器根本不考虑这些复制构造函数.
我可以通过自己做一点扭曲来做到这一点:
Fixture (static_cast <Root&> (*this))
…但我宁愿不是,因为它有点臭我的鼻子,非复制能力是我要通过派生Fixture从boost :: noncopyable的语义.
有没有办法阻止编译器在这种情况下考虑隐式声明的复制构造函数,而无需更改调用站点处的代码:
Fixture (*this)
?
>“不可能…”:标准C 03:12.8 / 4“特殊成员功能”:
If the class definition does not explicitly declare a copy
constructor,one is declared implicitly.
解决方法
诀窍是创建一个更好的匹配的重载.例如,
template <typename T> Fixture(T &)
将完全匹配任何左值,因此比需要转换的重载更好匹配.
然而,这太天真了,因为你实际上并不想让你的Fixture从任何东西都可以构建出来.相反,你希望它只能从根源派生的东西来构建.我们可以通过一些SFINAE魔法来禁用无关的构造函数.首先是C11版本:
#include <type_traits> template <typename T,typename = typename std::enable_if<std::is_base_of<Root,T>::value>::type> Fixture(T & x) : mRoot(x) { }
在C 03中,我们使用Boost,我们不能使用默认的模板参数:
#include <boost/type_traits.hpp> template <typename T> Fixture(T & x,typename boost::enable_if<boost::is_base_of<Root,T> >::type * = NULL) : mRoot(x) { }
现在你保证T是从Root派生的.这个模板化构造函数与T = Branch的重载是一个完全匹配,比复制构造函数更好,所以它被明确地选择为最好的重载.