gpt4 book ai didi

c++ - 如何在容器中指定模板化别名的通用类型

转载 作者:搜寻专家 更新时间:2023-10-31 02:05:24 25 4
gpt4 key购买 nike

我有一个类任务:

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 .


显然上面的解释不够清楚,所以这里是编译和工作的完整源代码:

#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\n"; return 5;});

x.addTask(task);
x.loop();
std::cout << "getValue<int> --> ";
auto valPtr = task->getValue<int>();
if (valPtr)
std::cout << *valPtr << '\n';
else
std::cout << "nullptr\n";
std::cout << "getValue<float> --> ";
auto valPtr2 = task->getValue<float>();
if (valPtr2)
std::cout << *valPtr2 << '\n';
else
std::cout << "nullptr\n";
}

关于c++ - 如何在容器中指定模板化别名的通用类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52096579/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com