我有一个模板构建器/工厂类,它创建Foo
类型的对象,其中make()
方法是模板方法,如下所示:
template<typename T1>
class FooMaker
{
template<typename T2>
Foo make(...) { ... }
};
这里的想法是T1
绑定到构建器,因为它对所有make()
调用都是相同的,而T2
(它总是一个函数名)通常是不同的make()
致电。
我多次调用make()
来创建不同类型的对象,模板类和模板函数的组合means I have to use the template
disambiguator before every call to make:
template <typename MAKER_T>
void make_some_foos()
{
auto maker = FooMaker<MAKER_T>(...);
Foo foo1 = maker.template make<Type1>(...);
Foo foo2 = maker.template make<Type2>(...);
// etc...
}
我想在构建上面template
的每一行上都需要Foo
关键字。一般来说,我在每个make()
对象上都有FooMaker
的多次调用,因此创建工厂时会有少量额外的代码。
显然我可以使用隐藏template
细节的宏来做到这一点,但是有一个很好的非宏解决方案 1 吗?
1 我可以将T1
和T2
移动到同一级别 - 通过使它们成为类模板参数或两个函数模板参数,但前者需要一个每个新类型T2
的独特制作者,后者意味着在每个T1
调用中冗余地指定相同的make
。
答案 0 :(得分:6)
这是std::get
是非成员函数的一个重要原因,而不是std::tuple
的成员。从该模式中获取一个想法,您可以创建一个非成员make_foo
:
template <typename T2, typename T1, typename... Args>
Foo make_foo( FooMaker<T1>& maker, Args&& ... args ) {
return maker.template make<T2>(std::forward<Args>(args)...);
}
然后就像使用它一样:
auto maker = ...; // some code to construct the builder
Foo foo1 = make_foo<Type1>(maker, ...);
Foo foo2 = make_foo<Type2>(maker, ...);
// etc...
答案 1 :(得分:2)
您可以确保推断出T2
。为此,您需要一个以某种方式提供信息的参数。这可能是一个简单的标签类型
template<typename T>
struct tag { using type = T; };
template<typename T1>
class FooMaker
{
template<typename T2>
Foo make_internal(...) { ... }
public:
template<typename Tag>
Foo make(Tag, ...)
{ return make_internal<Tag::type>(...); }
};
auto maker = ...; // some code to construct the builder
Foo foo1 = maker.make(tag<Type1>{}, ...);
Foo foo2 = maker.make(tag<Type2>{}, ...);
// etc...
或与特征类型组合的枚举,或者您只需使用指针传递类型:
template<typename T1>
class FooMaker
{
public:
template<typename T2>
Foo make(T2*, ...);
};
auto maker = ...; // some code to construct the builder
Foo foo1 = maker.make((Type1*)0, ...);
Foo foo2 = maker.make((Type2*)0, ...);
// etc...
虽然可以说,但这并不是很优雅。