繁体   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