静态方法中派生类的类型演绎
C++11, type deduction of derived class in static method
最小示例:
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);
这不是什么大问题,但重复似乎没有必要。有没有办法让它变成我想要的样子?
问题是MyTask::make
不是真的,而是Task::make
。在调用中使用的名称是查找的起点,而不是函数名称。所以严格来说没有重复。
您可以做不同的事情,例如,使用CRTP(正如Massa在评论中建议的那样)让派生类型将其类型注入到基础中-以不同基础的不同类型为代价,如果您有一些实际的接口,您将需要提供CRTP作为Task
和MyTask
之间的中间helper类型,或者更好地作为外部CRTP helper
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...);
}
你的问题没有意义,有几个不同的原因——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<...>
而不是原始指针。
辅助函数将是有价值的;模板实参推导可以通过它
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;
}
相关文章:
- 类型演绎 C++ 标准和自动
- λ类型演绎失败
- decltype(auto) 类型演绎:返回 x 与返回 (x)
- 使用decltype的动态多态类型演绎
- 普遍类型演绎scott-meyers
- c++ 11使用std::函数进行类型演绎
- 使用通用引用时进行类型演绎
- c++如何在无法进行类型演绎时调用模板化构造函数
- c#泛型中的类型演绎类似于c++模板
- 类型演绎不适用于std::function
- 为什么decltype返回类型在递归模板中失败,而返回类型演绎却工作得很好?
- 表达式模板中的按引用捕获可以与类型演绎共存
- 类型演绎模板函数c++
- 模板,类型演绎不足
- 括号初始化列表和函数模板类型演绎顺序
- 类型演绎的重载赋值操作符
- 静态方法中派生类的类型演绎
- 在类型演绎之后,函数模板中的替换顺序是否有任何保证
- 返回类型演绎是否可能
- c++ 14中赋值时的返回类型演绎