最小例子:
class Task
{
public:
template<typename T, typename... Args>
static T* make(Args... args) {
return new T(args...);
}
}
template<typename A, typename B, typename C>
class MyTask : public Task
{
public:
MyTask(A a, B b, C c)
{
}
}
存在make
工厂方法,以便在实例化模板化派生类时,不必提供所有模板类型。
我希望能够尽可能简洁地创建MyTask实例,即:
auto my_task = MyTask::make(a, b, c);
然而,编译器坚持认为它不能推断T,而是想要:
auto my_task = MyTask::make<MyTask<A, B, C>>(a, b, c);
这不是一个巨大的交易破坏者,但重复似乎是不必要的。有没有办法以我想要的方式获得它?
答案 0 :(得分:4)
问题在于MyTask::make
并非如此,而是Task::make
。您在调用中使用的名称是查找的起点,但不是函数名称。所以在技术上没有重复。
你可以做些不同的事情,例如,使用CRTP(正如Massa在评论中所建议的那样)让派生类型将它注入基础类型 - 具有不同的成本不同基础的类型,如果你有一些实际的接口,你需要提供CRTP作为Task
和MyTask
之间的中间帮助器类型,或者更好地作为外部CRTP帮助器
template <typename T>
struct Maker {
template <typename ...Args>
static T *make(Args ... args) { return new T(args...); }
};
class MyTask : public Maker<MyTask>, public Task { ... };
auto task = MyTask::make(a,b,c);
另一种方法是使函数成为自由函数,并仅传递您要构建的类型:
template <typename T, typename ...Args>
T* make(Args ... args);
auto x = make<MyTask>(a,b,c); // only named once here
要在模板的上述代码中支持 nice 语法而不必提供模板参数,您可以根据模板实现make
而不是类型:
template <template <typename...> class T,
typename ... Args>
T<Args...>* make(Args... args) {
return new T<Args...>(args...);
}
答案 1 :(得分:2)
由于几个不同的原因,您的问题没有意义 - make()
是Task
的成员,但您谈的是MyTask::make()
;您打算MyTask
来自Task
吗?另外,这里
auto my_task = MyTask::make<MyTask>(a, b, c);
// ^^^ ^^^
显然,如果不指定模板参数,则无法使用MyTask
。
我认为你试图展示的是这个(我添加了完美转发):
template<typename T>
class Task
{
public:
template<typename... Args>
static T* make(Args&&... args) {
return new T(std::forward<Args>(args)...);
}
};
template<typename A, typename B, typename C>
class MyTask : public Task<MyTask<A, B, C>>
{
public: MyTask(A, B, C) {}
};
你将它用作
auto my_task = MyTask<int, long, double>::make(10, 20L, 30.);
这是非常冗长的。这可以通过创建一个委托给Task::make()
的包装器函数来避免(或者在这个包装器本身中摆脱中间人并在Task::make
中完成工作,如果可行的话)
template<typename A, typename B, typename C>
MyTask<A, B, C> *make_MyTask(A&& a, B&& b, C&& c)
{
return Task<MyTask<A, B, C>>::make(std::forward<A>(a),
std::forward<B>(b),
std::forward<C>(c));
}
预期用途:
auto my_task = make_MyTask(10, 20L, 30.);
另一条建议是,您将make()
函数更改为返回unique_ptr<...>
而不是原始指针。
答案 2 :(得分:1)
辅助函数是有价值的;然后模板参数推导可以通过它发生
using namespace std;
template<typename T>
class Task
{
public:
template<typename... Args>
static T* make(Args... args)
{
return new T(args...);
}
};
// I find it easier to inherit from a class that actually knows what type to
// return in the "make" function
template<typename A, typename B, typename C>
class MyTask : public Task<MyTask<A, B, C>>
{
public:
MyTask(A a, B b, C c) { }
};
// basically this is the function, whose template argument deduction
// eliminates the need to manually specify the angle brackets
template<typename A, typename B, typename C>
MyTask<A, B, C>* MakeTask(A const& a, B const& b, C const& c) {
return MyTask<A, B, C>::make(a, b, c);
}
int main() {
// now usage only needs the function parameters. This scales to variadic args
auto my_task = MakeTask(1, 2, 3);
return 0;
}