我试图设计一个不可复制的对象,并阻止编译器考虑该类上隐式声明的复制构造函数.这是我正在开发的单元测试夹具.
考虑到我有两个主要对象:核心库对象,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的重载是一个完全匹配,比复制构造函数更好,所以它被明确地选择为最好的重载.