防止编译器在C 03中考虑隐式声明的复制构造函数

前端之家收集整理的这篇文章主要介绍了防止编译器在C 03中考虑隐式声明的复制构造函数前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
请注意,我正在C 03工作,C11的已删除功能不可用.

我试图设计一个不可复制的对象,并阻止编译器考虑该类上隐式声明的复制构造函数.这是我正在开发的单元测试夹具.

考虑到我有两个主要对象:核心库对象,Root和派生的特殊对象被测试,Branch.我正试图开发一个测试夹具类,Fixture处理细节的设置&与核心Root对象交谈.所以这是我迄今为止所建立的简单说明:

(Here is an ideone link与以下相同的代码,除了我已经定义了我自己的非复制)

  1. #include <boost/utility.hpp>
  2. #include <boost/noncopyable.hpp>
  3.  
  4. class Root
  5. {
  6. };
  7.  
  8. class Fixture
  9. :
  10. public boost::noncopyable
  11. {
  12. public:
  13. Fixture (Root& root)
  14. :
  15. mRoot (root)
  16. {
  17. }
  18. private:
  19. Root& mRoot;
  20. };
  21.  
  22. class Branch
  23. :
  24. public Root,public Fixture
  25. {
  26. public:
  27. Branch()
  28. :
  29. Fixture (*this)
  30. {
  31. }
  32. };
  33.  
  34. int main()
  35. {
  36. Branch branch;
  37. }

编译结果如下:

  1. main.cpp: In constructor Branch::Branch()’:
  2. main.cpp:30:23: error: call of overloaded Fixture(Branch&)’ is ambiguous
  3. main.cpp:30:23: note: candidates are:
  4. main.cpp:13:5: note: Fixture::Fixture(Root&)
  5. main.cpp:8:7: note: Fixture::Fixture(const Fixture&)

为了防止C 03编译器隐含地声明Fixture的复制构造函数是不可能的,除非我自己声明至少一个.但即使是:

  1. class Fixture
  2. :
  3. public boost::noncopyable
  4. {
  5. public:
  6. Fixture (Root& root)
  7. :
  8. mRoot (root)
  9. {
  10. }
  11. private:
  12. Fixture (const Fixture&);
  13. Fixture (Fixture&);
  14. Root& mRoot;
  15. };

…在Branch的初始化列表中初始化Fixture时,编译器仍然会考虑这些私有声明:

  1. Fixture (*this)

我希望编译器根本不考虑这些复制构造函数.

我可以通过自己做一点扭曲来做到这一点:

  1. Fixture (static_cast <Root&> (*this))

…但我宁愿不是,因为它有点臭我的鼻子,非复制能力是我要通过派生Fixture从boost :: noncopyable的语义.

有没有办法阻止编译器在这种情况下考虑隐式声明的复制构造函数,而无需更改调用站点处的代码

  1. Fixture (*this)

>“不可能…”:标准C 03:12.8 / 4“特殊成员功能”:

If the class definition does not explicitly declare a copy
constructor,one is declared implicitly.

解决方法

你的含糊之处在于*这可以绑定到一个Root&和Fixture&,这两个转换同样好(即派生到基础转换).

诀窍是创建一个更好的匹配的重载.例如,

  1. template <typename T> Fixture(T &)

将完全匹配任何左值,因此比需要转换的重载更好匹配.

然而,这太天真了,因为你实际上并不想让你的Fixture从任何东西都可以构建出来.相反,你希望它只能从根源派生的东西来构建.我们可以通过一些SFINAE魔法来禁用无关的构造函数.首先是C11版本:

  1. #include <type_traits>
  2.  
  3. template <typename T,typename = typename std::enable_if<std::is_base_of<Root,T>::value>::type>
  4. Fixture(T & x)
  5. : mRoot(x)
  6. { }

在C 03中,我们使用Boost,我们不能使用默认的模板参数:

  1. #include <boost/type_traits.hpp>
  2.  
  3. template <typename T>
  4. Fixture(T & x,typename boost::enable_if<boost::is_base_of<Root,T> >::type * = NULL)
  5. : mRoot(x)
  6. { }

现在你保证T是从Root派生的.这个模板化构造函数与T = Branch的重载是一个完全匹配,比复制构造函数更好,所以它被明确地选择为最好的重载.

猜你在找的C&C++相关文章