[英]Calling specialized template method from non-template class
我无法在非模板类中调用专用模板类中的方法。
我有一个如下所示的模板类:
template<class T>
class Builder{
Builder() { t = new T; }
Builder &setName(const int &name);
// other methods
T &build();
protected:
T *t;
}
template<class T>
T &Builder<T>::build() {
return *t;
}
// other implementations
我有一个继承自专门模板类的类
class SomeClass;
//template<class T>
class SomeClassBuilder : public Builder<SomeClass> {
public:
SomeClassBuilder() : Builder<SomeClass>() {}
SomeClassBuilder &setAge(int age);
}
class SomeClass{
public:
static SomeClassBuilder createExperiment(){
return {};
}
// other methods
}
但是,当我根据链接方法调用的方式尝试使用此 SomeClassBuilder 时,有时会出错。 下面的代码片段给出了一个错误( has no member named setAge
)。
SomeClass::Engine()
.setName("Name")
.setAge(109)
.build();
像下面这样链接方法调用不会出错,因为SomeClass
类的setAge
方法在模板类之前。
SomeClass::Engine()
.setAge(109)
.setName("Name")
.build();
您的问题是引用SomeClassBuilder &
可以解释为Builder<SomeClass> &
但不能Builder<SomeClass> &
解释(为此您需要动态转换)。 由于Builder<T>
的方法返回一个Builder<T> &
这确实没有set_age
成员。 这对模板来说没有问题,但在继承方面没有问题。
我看到了 3 个解决方案:
set_age
,而应用函数的类型仍然是SomeClassBuilder &
。SomeClassBuilder
所有函数,以便它们执行基类中的方法,然后将*this
作为SomeClassBuilder &
返回。class Child
添加到获取继承的 Child 类型的基类中,并让所有方法返回Child &
而不是Builder &
并且您必须在返回之前动态dynamic_cast
this
。 那么SomeClassBuilder
应该从Builder<T, SomeClassBuilder>
继承(需要前向声明)。 另外:不要使用原始指针来拥有内存。 在你的代码中出现一个new
并不是一个好兆头。 改用std::unique_ptr
。
Builder<SomeClass>::setName
返回Builder<SomeClass>
,它肯定没有任何setAge()
方法。 当您首先调用setAge()
,您会返回SomeClassBuilder
,并且它确实具有此方法,因此,此行为正是编译器所期望的。
要解决这个问题,您可以尝试使用CRTP返回一个实际的SomeClassBuilder
。
基本上,您的构建器定义将更改为
template <typename T, typename Derived>
class Builder
{
//...
Derived& setName();
//...
};
并且,对于SomeClassBuilder
:
class SomeClassBuilder: public Builder<T, SomeClassBuilder> { ... }
如果你想坚持你设计的方式,我认为除了使用CRTP之外别无选择。
更明确地说,这是一个工作示例,可能会对您有所帮助:
#include <memory>
template <typename OBJECT_TYPE, typename CRTP_BUILDER_IMPL>
class Builder
{
public:
Builder() : _p_object(std::make_unique<OBJECT_TYPE>()){};
CRTP_BUILDER_IMPL& impl() { return static_cast<CRTP_BUILDER_IMPL&>(*this); }
CRTP_BUILDER_IMPL& setName(const char* const& name)
{
// do the job using name ...
return impl();
};
protected:
std::unique_ptr<OBJECT_TYPE> _p_object;
};
template <typename OBJECT_TYPE>
class SomeClassBuilder : public Builder<OBJECT_TYPE, SomeClassBuilder<OBJECT_TYPE>>
{
using base_type = Builder<OBJECT_TYPE, SomeClassBuilder<OBJECT_TYPE>>;
public:
SomeClassBuilder() : base_type() {}
SomeClassBuilder& setAge(int age)
{
// do the job using age ...
return *this;
}
std::unique_ptr<OBJECT_TYPE> build() { return std::move(base_type::_p_object); }
};
class SomeClass
{
using builder_type = SomeClassBuilder<SomeClass>;
public:
static builder_type builder() { return builder_type(); }
};
int main()
{
auto someClass = SomeClass::builder().setName("Name").setAge(109).build();
auto someClass_2 = SomeClass::builder().setAge(109).setName("Name").build();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.