为了创建一个通用工厂,需要管理通用创建参数。
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;
}