从非模板类调用专门的模板方法

我无法在非模板类的专用模板类中调用方法。

我有一个如下的模板类:

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();

像下面那样束缚方法调用不会出错,因为setage类的Someclass方法位于模板类的前面。

Someclass::Engine()
            .setage(109)
            .setName("Name")
            .build();
nanren41 回答:从非模板类调用专门的模板方法

您的问题是引用SomeClassBuilder &可以解释为Builder<SomeClass> &,但反之则不行(为此您需要动态转换)。由于Builder<T>的方法返回Builder<T> &,因此它实际上没有set_age成员。这对模板没有问题,但对继承没有问题。

我看到3种解决方案:

  1. 始终首先使用set_age,而函数所应用的类型仍然是SomeClassBuilder &
  2. 重写SomeClassBuilder中的所有函数,以使它们执行基类中的方法,然后将*this作为SomeClassBuilder &返回。
  3. 使用CRTP,因此将模板参数class Child添加到基类,该参数获取继承的Child的类型,并让所有方法返回Child &而不是{{1} },那么您必须Builder & dynamic_cast才能返回。然后this应该继承自SomeClassBuilder(需要向前声明)。

也:不要使用原始指针来拥有内存。代码中的原始Builder<T,SomeClassBuilder>不是一个好兆头。请改用new

,

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();
}
本文链接:https://www.f2er.com/2992777.html

大家都在问