[英]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.