首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通用工厂方法和可变模板的问题

通用工厂方法和可变模板的问题
EN

Stack Overflow用户
提问于 2014-01-28 07:53:05
回答 2查看 1.1K关注 0票数 8

我想要创建一个类似于通用工厂方法的东西--看看这个:

代码语言:javascript
复制
template <class BaseType>
class Factory {
  public:
    template <class ... Args>
    static BaseType* Create(const Args& ... args) {
      return new DerivedType(args ...);
    }
};

其中,DerivedType是从BaseType派生并在另一个地方定义的其他类型。

问题在于如何存储DerivedType。例如,我想这样做:

代码语言:javascript
复制
void f() {
  // Derived type may have more than one constructor,
  // that's why I suggest using of the variadic templates.
  BaseType* ptr1 = Factory<BaseType>::Create("abc", 5, 10.);
  BaseType* ptr2 = Factory<BaseType>::Create();
  ...
}

...

Factory<BaseType>::SetType<MyDerivedType>();
f();

Factory<BaseType>::SetType<YourDerivedType>();
f();

我可以设置不同的派生类型,但它们在编译时都是已知的。我想不出一种合适的技术来做到这一点。

问题:,你能给我一个建议吗?

这样做的理由(因此,最初的问题,如果有人认为问题是它本身- XY问题)是一种能力单元-测试一些棘手的部分代码。例如,如果我有一个代码:

代码语言:javascript
复制
...
Shuttle* shuttle1 = new ShuttleImpl("Discovery", Destination::Moon);
Shuttle* shuttle2 = new ShuttleImpl();
...

每次运行单元测试时,我都不想真正构建航天飞机:

代码语言:javascript
复制
class Shuttle: public Factory<Shuttle> { ... }
...
Shuttle* shuttle1 = Shuttle::Create("Discovery", Destination::Moon);
Shuttle* shuttle2 = Shuttle::Create();
...

所以,在单元测试中,我可以这样做:Shuttle::SetType<TestShuttle>();

可能会有更多的“可测试”类,这就是为什么我需要一个通用工厂为所有这些:

代码语言:javascript
复制
class Car: public Factory<Car> { ... }
class Driver: public Factory<Driver> { ... }
...
EN

回答 2

Stack Overflow用户

发布于 2014-01-28 09:44:26

不是一个完整的答案,但是类模板的Create静态函数模板应该是:

代码语言:javascript
复制
template <class BaseType>
class Factory {
  public:
    template <class... Args>
    static BaseType* Create(Args&&... args) {
      return new DerivedType(std::forward<Args>(args)...);
    }
};

另见When to use std::forward to forward arguments?

编辑:

为什么第二个模板参数不能解决您的问题?

例如:

代码语言:javascript
复制
template <class Base, class Derived>
class Factory {
  public:
    template <class... Args>
    static Base* Create(Args&&... args) {
      return new Derived(std::forward<Args>(args)...);
    }
};

而不是

代码语言:javascript
复制
Factory<BaseType>::SetType<MyDerivedType>();
f();

Factory<BaseType>::SetType<YourDerivedType>();
f();

你可以写:

代码语言:javascript
复制
Factory<MyBase, MyDerived1> factory1;
Factory<MyBase, MyDerived2> factory2;

auto object1 = factory1::Create(1, "a");
auto object2 = factory2::Create(1.2, "abc");
票数 1
EN

Stack Overflow用户

发布于 2014-01-28 13:26:34

如果您的工厂知道所有可能的派生类,下面的内容可能会有所帮助:

代码语言:javascript
复制
// get_index<T, T1, .., TK-1, T, Ts...> is std::integral_constant<std::size_t, K>
template <typename T, typename ... Ts> struct get_index;

template <typename T, typename ... Ts>
struct get_index<T, T, Ts...> : std::integral_constant<std::size_t, 0> {};

template <typename T, typename Tail,  typename ... Ts>
struct get_index<T, Tail, Ts...> :
        std::integral_constant < std::size_t, 1 + get_index<T, Ts...>::value > {};

template <typename Base, typename...Deriveds>
struct Factory
{
private:
    template <typename Derivated, typename...Ts>
    static constexpr Base* allocator(Ts&&...args)
    {
        return new Derivated(std::forward<Ts>(args)...);
    }

    template <typename...Ts>
    static constexpr std::array<Base*(*)(Ts&&...), sizeof...(Deriveds)>
    array_alloc()
    {
        return std::array<Base*(*)(Ts&&...), sizeof...(Deriveds)>
            {{ &allocator<Deriveds, Ts&&...>... }};
    }

public:
    template <typename...Ts>
    static Base* create(Ts&&...args)
    {
        return array_alloc<Ts...>()[active](std::forward<Ts>(args)...);
    }

    template <typename Derived>
    static void setType()
    {
        active = get_index<Derived, Deriveds...>::value;
    }

private:
    static std::size_t active;
};

template <typename Base, typename...Deriveds>
std::size_t Factory<Base, Deriveds...>::active = 0;

并把它当作:

代码语言:javascript
复制
class Base {};

struct D1 : Base {
    D1() {std::cout << "D1" << std::endl;}
    D1(int a, int b) {}
};

struct D2 : Base {
    D2() {}
    D2(int a, int b) { std::cout << "D2(" << a << ", " << b << ")" << std::endl; }
};

int main(int argc, char *argv[])
{
    typedef Factory<Base, D1, D2> BaseFactory; // default to D1

    Base* b1 = BaseFactory::create(); // D1()
    BaseFactory::setType<D2>();
    Base* b2 = BaseFactory::create(42, 53); // D2(42, 53)

    delete b2;
    delete b1;

    return 0;
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21399791

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档