可变参数模板

时间:2017-09-12 15:55:00

标签: c++ templates variadic-templates c++17

为了创建一个通用工厂,需要管理通用创建参数。

这是第一步:

struct Foo {
    int num_;
    class FooKey {};
public:    
    Foo(int num, FooKey) : num_(num) {}
    static std::unique_ptr<Foo> create(int i) {
        return std::make_unique<Foo>(i, FooKey());
    }
    int num() const { return num_; }
};

template<class Obj>
class Factory {
public:
    template<typename... ObjParams>
    auto createObj(ObjParams&&... objectCreationParams) {
        // the use of C++17 std::invoke / std::apply is for conveniency
        // it can be done in a more cumbersome way with C++11/C++14
        return std::invoke(&Obj::create, objectCreationParams...);
    }
};

int main() {
    Factory<Foo> f;
    auto fObj = f.createObj(7);
    std::cout << fObj->num() << std::endl;
}

但是我们想让工厂'记住'创造参数。

因此我们添加了可变参数并为工厂寻找创建函数:

template<class Obj, class... ObjParams>
class Factory {

    std::tuple<ObjParams...> _objectCreationParams;

public:
    Factory(ObjParams&& ... params) {
        _objectCreationParams = 
            std::make_tuple<ObjParams...>(std::forward<ObjParams>(params)...);
    }

    auto createObj() {
        return std::apply(&Obj::create, _objectCreationParams);
    }
};

template<class Obj, class... ObjParams>
Factory<Obj, ObjParams...> createFactory(ObjParams&&... objParams) {
    return Factory<Obj, ObjParams...>{std::forward<ObjParams>(objParams)...};
}

int main() {
    auto factory = createFactory<Foo>(7);
    auto fObj = factory.createObj();
    std::cout << fObj->num() << std::endl;
}

我们想用C++17 class template argument deduction替换工厂的创建函数,但是无法编译(g ++ 7.2.0)。我想我错过了C ++ 17类模板参数推导规则。

有什么建议吗?

template<class Obj, class... ObjParams>
class Factory {

    // ...

public:
    template<class... ObjParams_>
    Factory(ObjParams_&& ... params) {
        _objectCreationParams = 
            std::make_tuple<ObjParams_...>(std::forward<ObjParams_>(params)...);
    }

    // ...
};

// user-defined deduction guide 
template<class Obj, class... ObjParams>
Factory(ObjParams&& ... params) -> Factory<Obj, ObjParams...>;

int main() {
    Factory<Foo> f(7); // compilation error - candidate expects 0 arguments, 1 provided
        // shouldn't it auto deduce <class... ObjParams> for Factory?
    auto fObj = f.createObj();
    std::cout << fObj->num() << std::endl;
}

编辑:

鉴于没有部分类模板参数推断,建议如下:

template<class Obj>
struct Factory {
    template<class... ObjParams>
    class WithParams {
        std::tuple<ObjParams...> _objectCreationParams;
    public:
        WithParams(ObjParams&& ... params) {
            _objectCreationParams = 
                std::make_tuple<ObjParams...>(std::forward<ObjParams>(params)...);
        }

        auto createObj() {
            return std::apply(&Obj::create, _objectCreationParams);
        }
    };
    template<class... ObjParams>
    auto createObj(ObjParams&& ... params) {
        return std::invoke(&Obj::create, std::forward<ObjParams>(params)...);
    }
};

int main() {
    Factory<Foo>::WithParams f(7);
    auto fObj = f.createObj();
    std::cout << fObj->num() << std::endl;

    Factory<Foo> f2;
    auto fObj2 = f2.createObj(8);
    std::cout << fObj2->num() << std::endl;
}

0 个答案:

没有答案