C++ 防止编译器考虑C+中隐式声明的复制构造函数+;03
请注意,我使用的是C++03,C++11的C++ 防止编译器考虑C+中隐式声明的复制构造函数+;03,c++,C++,请注意,我使用的是C++03,C++11的deleted函数对我不可用 我试图设计一个不可复制的对象,并阻止编译器考虑该类上隐式声明的复制构造函数。这是我正在开发的单元测试夹具 假设我有两个主要对象:一个核心库对象,Root,一个派生的测试中的特殊情况对象,Branch。我正在尝试开发一个测试夹具类,fixture,它处理设置核心根对象并与之对话的细节。这是我到目前为止构建的一个简化示例: (与下面的代码相同,只是我定义了自己的noncopyable) 除非我自己至少声明了一个副本构造函数,否则
delete
d函数对我不可用
我试图设计一个不可复制的对象,并阻止编译器考虑该类上隐式声明的复制构造函数。这是我正在开发的单元测试夹具
假设我有两个主要对象:一个核心库对象,Root
,一个派生的测试中的特殊情况对象,Branch
。我正在尝试开发一个测试夹具类,fixture
,它处理设置核心根对象并与之对话的细节。这是我到目前为止构建的一个简化示例:
(与下面的代码相同,只是我定义了自己的noncopyable
)
除非我自己至少声明了一个副本构造函数,否则无法*阻止C++03编译器隐式声明Fixture
的副本构造函数。但即使:
class Fixture
:
public boost::noncopyable
{
public:
Fixture (Root& root)
:
mRoot (root)
{
}
private:
Fixture (const Fixture&);
Fixture (Fixture&);
Root& mRoot;
};
<> >编译器在“<代码>分支/<代码>初始化列表:初始化<代码>夹具<代码>时仍要考虑这些代码>私下<代码> >声明
Fixture (*this)
< >我希望编译器不要简单地考虑这些复制构造函数。
我可以通过自己做一些扭曲来做到这一点:
Fixture (static_cast <Root&> (*this))
?
- “不可能…”:标准C++03:12.8/4,“特殊成员函数”:
如果类定义没有显式声明副本
构造函数,则隐式声明一个
在C++98和C++11中都无法防止复制构造函数签名的存在=delete
也不会从重载集中删除某些内容,只有在选中时才会失败
如果不想弄乱Fixture的公共接口,我没有比插入显式cast更好的主意
不影响接口的选项包括通过指针传递根
,以区别于复制构造函数的引用,以及为了重载解析而传递标记。如果您想了解更多关于这些的信息,请留下评论。如果您不打算将分支
作为Fixture
的实例传递,则根本不需要继承它。如果我没有弄错的话,您基本上希望能够在Fixture
中为Root
的所有实例设置一些东西。所以让我们来攻击这个原因,而不是弯曲C++。strong>免责声明:如果不是这样,恐怕我没有任何建议
对于这个问题,我将使Branch
有一个Fixture
的实例作为它的成员,并重载复制Branch
的构造函数来创建Fixture
的实例,方法是将自身作为实例传递给Fixture
的构造函数,并将赋值操作符传递给Fixture
实例。下面是一个简单的例子:
#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:
Branch()
: mFixture(*this)
{
}
Branch(const Branch& branch)
: Root(*this)
, mFixture(*this)
/* other 'Branch' members to be copied */
{
}
Branch& operator = (const Branch& branch)
{
Root::operator=(branch);
/* copy other 'Branch' members, except 'mFixture' */
}
Fixture& getFixture()
{
return mFixture;
}
const Fixture& getFixture() const
{
return mFixture;
}
private:
Fixture mFixture;
};
#包括
#包括
类根
{
};
班级固定装置
:
公共增强::不可复制
{
公众:
固定装置(根部和根部)
:
mRoot(根)
{
}
私人:
根与根;
};
班支部
:
公共根
{
公众:
分支机构()
:mFixture(*此)
{
}
分公司(施工分公司和分公司)
:Root(*this)
,mFixture(*此)
/*要复制的其他“分支”成员*/
{
}
分支和运算符=(常量分支和分支)
{
根::运算符=(分支);
/*复制除“mFixture”之外的其他“分支”成员*/
}
Fixture&getFixture()
{
返回mFixture;
}
常量Fixture&getFixture()常量
{
返回mFixture;
}
私人:
夹具制造;
};
您的含糊不清之处在于,*此
可以绑定到根&
和夹具&
,并且两种转换都同样好(即派生到基转换)
诀窍是创建一个更好匹配的重载。比如说,
template <typename T> Fixture(T &)
在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&x、,
typename boost::enable_if::type*=NULL)
:mRoot(x)
{ }
现在可以保证T
是从Root
派生的。此模板化构造函数的重载与T=Branch
完全匹配,优于复制构造函数,因此它被明确地选为最佳重载。C++11中删除的函数会有帮助吗?被删除的函数仍然参与重载解析。@KerrekSB:老实说,我不知道。如果你认为他们参与解决方案是对的,那么我认为他们不会有帮助。我认为a应该毫无疑问地优先……@KerrekSB:Aha。您的示例使用C++11,但我可以使用它。Boost中有相应的特性…+1我可以传递指针,但我宁愿传递引用,因为我将存储引用。如果我改变ctor以获取指针,那么无论如何我都必须改变呼叫站点代码,因此我想我更喜欢这种情况下的静态\u cast
。顺便说一句,我很乐意搞乱Fixture
的公共
界面,只要我不改变分支
中的呼叫站点代码,对于分支&
,此重载不再可行。也许是可转换的
。我忍不住觉得SFINAE的魔力有点过火了。总之,使用一个简单的模板
构造函数(非SFINAE),如果我传递一些不可转换的东西(比如FooBar
),它无论如何都会编译失败。这显然不起作用,因为是相同的
在这种情况下不会编译,正如我所说的,我使用的是C++03。我会解决它。@johndilling:如果你不想让构造函数污染你的类,你绝对需要SFINAE。重载解析并不关心主体是否会编译。您需要删除不需要的重载
#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:
Branch()
: mFixture(*this)
{
}
Branch(const Branch& branch)
: Root(*this)
, mFixture(*this)
/* other 'Branch' members to be copied */
{
}
Branch& operator = (const Branch& branch)
{
Root::operator=(branch);
/* copy other 'Branch' members, except 'mFixture' */
}
Fixture& getFixture()
{
return mFixture;
}
const Fixture& getFixture() const
{
return mFixture;
}
private:
Fixture mFixture;
};
template <typename T> Fixture(T &)
#include <type_traits>
template <typename T,
typename = typename std::enable_if<std::is_base_of<Root, T>::value>::type>
Fixture(T & x)
: mRoot(x)
{ }
#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)
{ }