簡體   English   中英

從非模板類調用專門的模板方法

[英]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 個解決方案:

  1. 始終首先使用set_age ,而應用函數的類型仍然是SomeClassBuilder &
  2. 覆蓋SomeClassBuilder所有函數,以便它們執行基類中的方法,然后將*this作為SomeClassBuilder &返回。
  3. 使用CRTP ,因此將模板參數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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM