我目前正在尝试用C ++实现mixin类。我几乎有我想要的行为。然而,关于传递mixin的基类参数有一个问题:如果基类需要对不可复制对象的const引用,那么代码就无法编译。
正如您在下面的代码示例中看到的那样。类WidgetBase
编译正常,MetaWidgetBase
得到编译器错误:
#include <iostream>
#include <string>
#include <typeinfo>
class WidgetBase
{
public:
WidgetBase(WidgetBase * inParent, const std::string & inTitle) :
mParent(inParent),
mTitle(inTitle)
{
}
virtual ~WidgetBase() { }
private:
WidgetBase * mParent;
std::string mTitle;
};
class MetaWidgetBase
{
public:
MetaWidgetBase(const std::type_info & inTypeInfo) : mTypeInfo(inTypeInfo) {}
virtual ~MetaWidgetBase(){}
private:
const std::type_info & mTypeInfo;
};
template<class SuperType>
class Resizable : public SuperType
{
typedef SuperType Super;
public:
void resize(int width, int height) {}
protected:
Resizable() {}
template<class Arg0>
Resizable(Arg0 arg0) : Super(arg0) {}
template<class Arg0, class Arg1>
Resizable(Arg0 arg0, Arg1 arg1) : Super(arg0, arg1) {}
template<class Arg0, class Arg1, class Arg2>
Resizable(Arg0 arg0, Arg1 arg1, Arg2 arg2) : Super(arg0, arg1, arg2) {}
template<class Arg0, class Arg1, class Arg2, class Arg3>
Resizable(Arg0 arg0, Arg1 arg1, Arg2 arg2, Arg3 arg3) : Super(arg0, arg1, arg2, arg3) {}
};
template<class SuperType>
class Movable : public SuperType
{
typedef SuperType Super;
public:
void move(int x, int y) {}
protected:
Movable() {}
template<class Arg0>
Movable(Arg0 arg0) : Super(arg0) {}
template<class Arg0, class Arg1>
Movable(Arg0 arg0, Arg1 arg1) : Super(arg0, arg1) {}
template<class Arg0, class Arg1, class Arg2>
Movable(Arg0 arg0, Arg1 arg1, Arg2 arg2) : Super(arg0, arg1, arg2) {}
template<class Arg0, class Arg1, class Arg2, class Arg3>
Movable(Arg0 arg0, Arg1 arg1, Arg2 arg2, Arg3 arg3) : Super(arg0, arg1, arg2, arg3) {}
};
class MyWidget : public Resizable<Movable<WidgetBase> >
{
typedef Resizable<Movable<WidgetBase> > Super;
public:
MyWidget(WidgetBase * inParent, const std::string & inTitle) :
Super(inParent, inTitle)
{
}
};
class MyMetaWidget : public Resizable<MetaWidgetBase>
{
typedef Resizable<MetaWidgetBase> Super;
public:
MyMetaWidget() :
Super(typeid(this))
{
}
};
int main()
{
// Works fine:
MyWidget widget(NULL, "Hello");
// Error: std::type_info has private copy constructor!
MyMetaWidget metaWidget;
return 0;
}
确切的错误信息是:
/usr/include/c++/4.2.1/typeinfo: In constructor 'MyMetaWidget::MyMetaWidget()':
/usr/include/c++/4.2.1/typeinfo:135: error: 'std::type_info::type_info(const std::type_info&)' is private
我目前的解决方法是将std :: type_info对象作为const指针而不是const引用传递。
有没有人如何妥善处理这个问题?
似乎在转发期间,模板参数只会松散其类型签名的引用部分。其余的都没有受到伤害。这也意味着如果我们使用“ArgN&amp;”作为参数类型,我们是安全的。
所以基本上解决方案是这样的:让mixin类的构造函数将其所有参数作为非const引用。
这是我的测试各种组合(GCC)的示例应用程序:
#include <iostream>
#include <string>
#include <typeinfo>
#define TRACE std::cout << __PRETTY_FUNCTION__ << std::endl << std::flush;
#define TRACE_MIXIN std::cout << __PRETTY_FUNCTION__ << std::endl << std::flush;
#define TRACE_BASE std::cout << "\n" << __PRETTY_FUNCTION__ << std::endl << std::flush;
// Savable is a mixin class for saving object state to file.
template<class BaseType>
struct Savable : public BaseType {
Savable() {
TRACE_MIXIN
}
template<class Arg0>
Savable(Arg0 & arg0) : BaseType(arg0) {
TRACE_MIXIN
}
template<class Arg0, class Arg1>
Savable(Arg0 & arg0, Arg1 & arg1) : BaseType(arg0, arg1) {
TRACE_MIXIN
}
void Save(const std::string & inFileName) {}
};
// Loadable is a mixin class for load object state from file.
template<class BaseType>
struct Loadable : public BaseType {
Loadable() {
TRACE_MIXIN
}
template<class Arg0>
Loadable(Arg0 & arg0) : BaseType(arg0) {
TRACE_MIXIN
}
template<class Arg0, class Arg1>
Loadable(Arg0 & arg0, Arg1 & arg1) : BaseType(arg0, arg1) {
TRACE_MIXIN
}
void Load(const std::string & inFileName) {}
};
// Test with a copyable constructor args
namespace CopyLand {
struct MyObject {}; // copyable
struct ValueBase {
ValueBase(MyObject inObject, const std::string & inTest) :
mObject(inObject), mTest(inTest) {
TRACE_BASE
}
MyObject mObject;
std::string mTest;
};
struct ConstValueBase {
ConstValueBase(const MyObject inObject, const std::string & inTest) :
mObject(inObject), mTest(inTest) {
TRACE_BASE
}
const MyObject mObject;
std::string mTest;
};
struct PtrBase {
PtrBase(MyObject * inObject, const std::string & inTest) :
mObject(inObject), mTest(inTest) {
TRACE_BASE
}
MyObject * mObject;
std::string mTest;
};
struct ConstPtrBase {
ConstPtrBase(const MyObject * inObject, const std::string & inTest) :
mObject(inObject), mTest(inTest) {
TRACE_BASE
}
const MyObject * mObject;
std::string mTest;
};
struct RefBase {
RefBase(MyObject & inObject, const std::string & inTest) :
mObject(inObject), mTest(inTest) {
TRACE_BASE
}
MyObject & mObject;
std::string mTest;
};
struct ConstRefBase {
ConstRefBase(const MyObject & inObject, const std::string & inTest) :
mObject(inObject), mTest(inTest) {
TRACE_BASE
}
const MyObject & mObject;
std::string mTest;
};
struct LoadableAndSavableValueBase : public Loadable<Savable<ValueBase> > {
LoadableAndSavableValueBase(MyObject inObject, const std::string & inTest) :
Loadable<Savable<ValueBase> >(inObject, inTest) {
TRACE
}
};
struct LoadableAndSavableConstValueBase : public Loadable<Savable<ConstValueBase> > {
LoadableAndSavableConstValueBase(const MyObject inObject, const std::string & inTest) :
Loadable<Savable<ConstValueBase> >(inObject, inTest) {
TRACE
}
};
struct LoadableAndSavablePtrBase : public Loadable<Savable<PtrBase> > {
LoadableAndSavablePtrBase(MyObject * inObject, const std::string & inTest) :
Loadable<Savable<PtrBase> >(inObject, inTest) {
TRACE
}
};
struct LoadableAndSavableRefBase : public Loadable<Savable<RefBase> > {
LoadableAndSavableRefBase(MyObject & inObject, const std::string & inTest) :
Loadable<Savable<RefBase> >(inObject, inTest) {
TRACE
}
};
struct LoadableAndSavableConstPtrBase : public Loadable<Savable<ConstPtrBase> > {
LoadableAndSavableConstPtrBase(const MyObject * inObject, const std::string & inTest) :
Loadable<Savable<ConstPtrBase> >(inObject, inTest) {
TRACE
}
};
struct LoadableAndSavableConstRefBase : public Loadable<Savable<ConstRefBase> > {
LoadableAndSavableConstRefBase(const MyObject & inObject, const std::string & inTest) :
Loadable<Savable<ConstRefBase> >(inObject, inTest) {
TRACE
}
};
void test() {
MyObject myObject;
LoadableAndSavableValueBase valueBase(myObject, "Test");
LoadableAndSavableConstValueBase constValueBase(myObject, "Test");
LoadableAndSavablePtrBase ptrBase(&myObject, "Test");
LoadableAndSavableConstPtrBase constPtrBase(&myObject, "Test");
LoadableAndSavableRefBase refBase(myObject, "Test");
LoadableAndSavableConstRefBase constRefBase(myObject, "Test");
}
} // namespace CopyLand
namespace NoCopyLand { // Test with a noncopyable Arg0 object
struct MyObject {
MyObject() {}
// noncopyable
MyObject(const MyObject&);
const MyObject& operator=(const MyObject&);
};
struct PtrBase {
PtrBase(MyObject * inObject, const std::string & inTest) :
mObject(inObject), mTest(inTest) {
TRACE_BASE
}
MyObject * mObject;
std::string mTest;
};
struct ConstPtrBase {
ConstPtrBase(const MyObject * inObject, const std::string & inTest) :
mObject(inObject), mTest(inTest) {
TRACE_BASE
}
const MyObject * mObject;
std::string mTest;
};
struct RefBase {
RefBase(MyObject & inObject, const std::string & inTest) :
mObject(inObject), mTest(inTest) {
TRACE_BASE
}
MyObject & mObject;
std::string mTest;
};
struct ConstRefBase {
ConstRefBase(const MyObject & inObject, const std::string & inTest) :
mObject(inObject), mTest(inTest) {
TRACE_BASE
}
const MyObject & mObject;
std::string mTest;
};
struct LoadableAndSavablePtrBase : public Loadable<Savable<PtrBase> > {
LoadableAndSavablePtrBase(MyObject * inObject, const std::string & inTest) :
Loadable<Savable<PtrBase> >(inObject, inTest) {
TRACE
}
};
struct LoadableAndSavableRefBase : public Loadable<Savable<RefBase> > {
LoadableAndSavableRefBase(MyObject & inObject, const std::string & inTest) :
Loadable<Savable<RefBase> >(inObject, inTest) {
TRACE
}
};
struct LoadableAndSavableConstPtrBase : public Loadable<Savable<ConstPtrBase> > {
LoadableAndSavableConstPtrBase(const MyObject * inObject, const std::string & inTest) :
Loadable<Savable<ConstPtrBase> >(inObject, inTest) {
TRACE
}
};
struct LoadableAndSavableConstRefBase : public Loadable<Savable<ConstRefBase> > {
LoadableAndSavableConstRefBase(const MyObject & inObject, const std::string & inTest) :
Loadable<Savable<ConstRefBase> >(inObject, inTest) {
TRACE
}
};
// Also include a test with std::type_info.
struct TypeInfo {
TypeInfo(const std::type_info & inTypeInfo) : mTypeInfo(inTypeInfo) {}
const std::type_info & mTypeInfo;
};
struct LoadableAndSavableTypeInfo : public Loadable<Savable<TypeInfo> > {
LoadableAndSavableTypeInfo() : Loadable<Savable<TypeInfo> >(typeid(this)) {}
};
void test() {
MyObject myObject;
LoadableAndSavablePtrBase ptrBase(&myObject, "Test");
LoadableAndSavableConstPtrBase constPtrBase(&myObject, "Test");
LoadableAndSavableRefBase refBase(myObject, "Test");
LoadableAndSavableConstRefBase constRefBase(myObject, "Test");
LoadableAndSavableTypeInfo typeInfo;
typeInfo.mTypeInfo.name(); // get the std::type_info
}
} // namespace NoCopyLand
int main() {
CopyLand::test();
NoCopyLand::test();
return 0;
}
运行程序时,它会产生以下输出:
g++ -o test main.cpp
CopyLand::ValueBase::ValueBase(CopyLand::MyObject, const std::string&)
Savable<BaseType>::Savable(Arg0&, Arg1&) [with Arg0 = CopyLand::MyObject, Arg1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, BaseType = CopyLand::ValueBase]
Loadable<BaseType>::Loadable(Arg0&, Arg1&) [with Arg0 = CopyLand::MyObject, Arg1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, BaseType = Savable<CopyLand::ValueBase>]
CopyLand::LoadableAndSavableValueBase::LoadableAndSavableValueBase(CopyLand::MyObject, const std::string&)
CopyLand::ConstValueBase::ConstValueBase(CopyLand::MyObject, const std::string&)
Savable<BaseType>::Savable(Arg0&, Arg1&) [with Arg0 = const CopyLand::MyObject, Arg1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, BaseType = CopyLand::ConstValueBase]
Loadable<BaseType>::Loadable(Arg0&, Arg1&) [with Arg0 = const CopyLand::MyObject, Arg1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, BaseType = Savable<CopyLand::ConstValueBase>]
CopyLand::LoadableAndSavableConstValueBase::LoadableAndSavableConstValueBase(CopyLand::MyObject, const std::string&)
CopyLand::PtrBase::PtrBase(CopyLand::MyObject*, const std::string&)
Savable<BaseType>::Savable(Arg0&, Arg1&) [with Arg0 = CopyLand::MyObject*, Arg1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, BaseType = CopyLand::PtrBase]
Loadable<BaseType>::Loadable(Arg0&, Arg1&) [with Arg0 = CopyLand::MyObject*, Arg1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, BaseType = Savable<CopyLand::PtrBase>]
CopyLand::LoadableAndSavablePtrBase::LoadableAndSavablePtrBase(CopyLand::MyObject*, const std::string&)
CopyLand::ConstPtrBase::ConstPtrBase(const CopyLand::MyObject*, const std::string&)
Savable<BaseType>::Savable(Arg0&, Arg1&) [with Arg0 = const CopyLand::MyObject*, Arg1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, BaseType = CopyLand::ConstPtrBase]
Loadable<BaseType>::Loadable(Arg0&, Arg1&) [with Arg0 = const CopyLand::MyObject*, Arg1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, BaseType = Savable<CopyLand::ConstPtrBase>]
CopyLand::LoadableAndSavableConstPtrBase::LoadableAndSavableConstPtrBase(const CopyLand::MyObject*, const std::string&)
CopyLand::RefBase::RefBase(CopyLand::MyObject&, const std::string&)
Savable<BaseType>::Savable(Arg0&, Arg1&) [with Arg0 = CopyLand::MyObject, Arg1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, BaseType = CopyLand::RefBase]
Loadable<BaseType>::Loadable(Arg0&, Arg1&) [with Arg0 = CopyLand::MyObject, Arg1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, BaseType = Savable<CopyLand::RefBase>]
CopyLand::LoadableAndSavableRefBase::LoadableAndSavableRefBase(CopyLand::MyObject&, const std::string&)
CopyLand::ConstRefBase::ConstRefBase(const CopyLand::MyObject&, const std::string&)
Savable<BaseType>::Savable(Arg0&, Arg1&) [with Arg0 = const CopyLand::MyObject, Arg1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, BaseType = CopyLand::ConstRefBase]
Loadable<BaseType>::Loadable(Arg0&, Arg1&) [with Arg0 = const CopyLand::MyObject, Arg1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, BaseType = Savable<CopyLand::ConstRefBase>]
CopyLand::LoadableAndSavableConstRefBase::LoadableAndSavableConstRefBase(const CopyLand::MyObject&, const std::string&)
NoCopyLand::PtrBase::PtrBase(NoCopyLand::MyObject*, const std::string&)
Savable<BaseType>::Savable(Arg0&, Arg1&) [with Arg0 = NoCopyLand::MyObject*, Arg1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, BaseType = NoCopyLand::PtrBase]
Loadable<BaseType>::Loadable(Arg0&, Arg1&) [with Arg0 = NoCopyLand::MyObject*, Arg1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, BaseType = Savable<NoCopyLand::PtrBase>]
NoCopyLand::LoadableAndSavablePtrBase::LoadableAndSavablePtrBase(NoCopyLand::MyObject*, const std::string&)
NoCopyLand::ConstPtrBase::ConstPtrBase(const NoCopyLand::MyObject*, const std::string&)
Savable<BaseType>::Savable(Arg0&, Arg1&) [with Arg0 = const NoCopyLand::MyObject*, Arg1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, BaseType = NoCopyLand::ConstPtrBase]
Loadable<BaseType>::Loadable(Arg0&, Arg1&) [with Arg0 = const NoCopyLand::MyObject*, Arg1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, BaseType = Savable<NoCopyLand::ConstPtrBase>]
NoCopyLand::LoadableAndSavableConstPtrBase::LoadableAndSavableConstPtrBase(const NoCopyLand::MyObject*, const std::string&)
NoCopyLand::RefBase::RefBase(NoCopyLand::MyObject&, const std::string&)
Savable<BaseType>::Savable(Arg0&, Arg1&) [with Arg0 = NoCopyLand::MyObject, Arg1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, BaseType = NoCopyLand::RefBase]
Loadable<BaseType>::Loadable(Arg0&, Arg1&) [with Arg0 = NoCopyLand::MyObject, Arg1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, BaseType = Savable<NoCopyLand::RefBase>]
NoCopyLand::LoadableAndSavableRefBase::LoadableAndSavableRefBase(NoCopyLand::MyObject&, const std::string&)
NoCopyLand::ConstRefBase::ConstRefBase(const NoCopyLand::MyObject&, const std::string&)
Savable<BaseType>::Savable(Arg0&, Arg1&) [with Arg0 = const NoCopyLand::MyObject, Arg1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, BaseType = NoCopyLand::ConstRefBase]
Loadable<BaseType>::Loadable(Arg0&, Arg1&) [with Arg0 = const NoCopyLand::MyObject, Arg1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, BaseType = Savable<NoCopyLand::ConstRefBase>]
NoCopyLand::LoadableAndSavableConstRefBase::LoadableAndSavableConstRefBase(const NoCopyLand::MyObject&, const std::string&)
Savable<BaseType>::Savable(Arg0&) [with Arg0 = const std::type_info, BaseType = NoCopyLand::TypeInfo]
Loadable<BaseType>::Loadable(Arg0&) [with Arg0 = const std::type_info, BaseType = Savable<NoCopyLand::TypeInfo>]
如果我的例子或结论中有任何错误,请告诉我。)
答案 0 :(得分:2)
您在mixin类中按值ArgN
。您可以尝试Movable(Arg0 const& arg0, Arg1 const& arg1)
,同样也可以Resizable
。