如何在容器中指定模板化别名'泛型类型
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在容器中指定模板化别名'泛型类型相关的知识,希望对你有一定的参考价值。
我有一个课程任务:
template <typename T>
class Task {
Task(const std::function<T()>& func)
: m_func(func)
{
// some stuff here
}
std::shared_ptr<T> getValue() {
return m_value;
}
void execute() {
m_value = std::make_shared<T>(m_func());
}
std::shared_ptr<T> m_value;
std::function<T()> m_func;
}
现在,我想将此Task类别名为shared_ptr,所以我执行以下操作...
template <typename T> using TaskPtr = std::shared_ptr<Task<T> >;
我有另一个类将存储一个TaskPtr的容器,我希望api的使用者在调用addTask时指定T,如下所示。
Class X {
// some boiler plate code
template <typename T>
addTask(TaskPtr<T> task) {
m_queue.push(task);
}
void loop() {
// do some stuff
auto item = m_queue.front();
item->execute();
m_queue.pop();
// continue looping
}
std::queue<TaskPtr<T> > m_queue;
}
我想知道最好的办法是什么。这段代码给出了T未定义的错误。咄!我需要在我的template <tyepname T>
定义之上添加m_queue
,这是有道理的。当我这样做时,我得到的是我将关键字typedef
放在一个不正确的位置。当我删除模板声明和T
只有std::queue<Taskptr> m_queue;
时,它告诉我我错过了一个模板参数。这是有道理的,除了我不明白应该去哪里。
我找了一个答案,找不到任何东西。我正在尝试做什么是正确的语法实现?
错误发生在:
class X {
....
std::queue<TaskPtr<T> > m_queue; // <--- T is unknown
};
此时,编译器想知道任务的类型是什么,但您只想存储所有任务,而不管其类型如何。要弄清楚如何使这项工作,看看T
的用途,看看如何摆脱它。
template <typename T>
class Task {
std::shared_ptr<T> getValue() {
return m_value;
}
void execute() {
m_value = std::make_shared<T>(m_func());
}
....
};
如果它只是execute
然后生活会很简单,正确的execute()
的调用者并不关心T
是什么,只是操作被执行。如果只是那个,那么解决方案将是微不足道的:
class TaskBase
{
public:
virtual ~TaskBase() = default;
TaskBase(const TaskBase &) = default; // and so on....
virtual void execute() = 0;
};
template <typename T>
class Task : public TaskBase {
....
};
然后,只需存储指向TaskBase
而不是Task<T>
的指针。
解决getValue()
稍微复杂一些。你需要使用从TaskBase动态转换为getValue<T>()
的实际任务:
template <typename T>
std::shared_ptr<T> Task<T>::getValue() {
return m_value;
}
template<typename T>
std::shared_ptr<T> TaskBase::getValue()
{
auto childThis = dynamic_cast<Task<T>*>(this);
if (childThis == nullptr) {
// or maybe throw an exception
return nullptr;
}
return childThis->getValue();
}
使用更棘手,因为用户必须知道任务中存储的类型:
void foo(std::shared_ptr<TaskBase> ptr)
{
auto ifInt = ptr->getValue<int>();
auto ifDouble = ptr->getValue<double>();
... more code ..
}
在这种情况下,Task<int>
将检测到ifInt
,但是由于Task<unsigned>
,ifInt==nullptr
会失败。
Apparently the above explanation is not clear enough, so here is the complete source that compiles and works:
#include <memory>
#include <functional>
#include <queue>
#include <iostream>
class TaskBase
{
public:
virtual ~TaskBase() = default;
TaskBase() = default;
TaskBase(const TaskBase &) = default; // and so on....
virtual void execute() = 0;
template <typename T>
std::shared_ptr<T> getValue();
};
template <typename T>
class Task : public TaskBase {
public:
Task(const std::function<T()>& func)
: m_func(func)
{
// some stuff here
}
void execute() override {
m_value = std::make_shared<T>(m_func());
}
std::shared_ptr<T> getValue() {
return m_value;
}
private:
std::shared_ptr<T> m_value;
std::function<T()> m_func;
};
template <typename T>
std::shared_ptr<T> TaskBase::getValue()
{
auto downCast = dynamic_cast<Task<T>*>(this);
if (downCast)
return downCast->getValue();
else
return nullptr;
}
using TaskPtr = std::shared_ptr<TaskBase>;
class X {
// some boiler plate code
public:
void addTask(TaskPtr task) {
m_queue.push(task);
}
void loop() {
// do some stuff
auto item = m_queue.front();
item->execute();
m_queue.pop();
// continue looping
}
std::queue<TaskPtr> m_queue;
};
int main()
{
X x;
TaskPtr task = std::make_shared<Task<int>>(
[] { std::cout << "int task execution
"; return 5;});
x.addTask(task);
x.loop();
std::cout << "getValue<int> --> ";
auto valPtr = task->getValue<int>();
if (valPtr)
std::cout << *valPtr << '
';
else
std::cout << "nullptr
";
std::cout << "getValue<float> --> ";
auto valPtr2 = task->getValue<float>();
if (valPtr2)
std::cout << *valPtr2 << '
';
else
std::cout << "nullptr
";
}
以上是关于如何在容器中指定模板化别名'泛型类型的主要内容,如果未能解决你的问题,请参考以下文章
在定义单个 AWS::Serverless::Function 的 SAM 模板中指定多个 API 阶段和 Lambda 别名