C++ 如何指定模板化别名';容器中的泛型类型
我有一个课堂任务:C++ 如何指定模板化别名';容器中的泛型类型,c++,c++11,templates,polymorphism,type-erasure,C++,C++11,Templates,Polymorphism,Type Erasure,我有一个课堂任务: 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 e
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;
}
模板
课堂任务{
任务(const std::function和func)
:m_func(func)
{
//这里有些东西
}
std::shared_ptr getValue(){
返回m_值;
}
void execute(){
m_value=std::使_共享(m_func());
}
std::共享_ptr m_值;
std::函数m_func;
}
现在,我想将此任务类别名为共享的\u ptr,因此我执行以下操作
使用TaskPtr=std::shared\u ptr的模板代码>
我有另一个类,它将存储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;
}
X类{
//一些锅炉铭牌代码
模板
addTask(TaskPtr任务){
m_queue.push(任务);
}
void循环(){
//做点什么
auto item=m_queue.front();
项目->执行();
m_queue.pop();
//继续循环
}
std::队列m_队列;
}
我想知道最好的方法是什么。这段代码给我一个错误,T是未定义的。哼!我需要在我的m_队列
定义上方添加模板
,这很有意义。当我这样做时,我发现我把关键字typedef
放在了一个错误的位置。当我删除模板声明和T
时,只需要std::queue m_queue代码>,它告诉我缺少一个模板参数。这是有道理的,但我不明白它应该放在哪里
我一直在寻找答案,但什么也找不到。对于我正在尝试的操作,正确的语法实现是什么?错误在于:
class X {
....
std::queue<TaskPtr<T> > m_queue; // <--- T is unknown
};
如果只执行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 {
....
};
由于用户必须知道任务中存储的类型,因此使用更为棘手:
void foo(std::shared_ptr<TaskBase> ptr)
{
auto ifInt = ptr->getValue<int>();
auto ifDouble = ptr->getValue<double>();
... more code ..
}
“我需要在我的m_队列定义上方添加模板”-否:您必须在您的类X上方添加模板
definition@max66,嗨,麦克斯,谢谢你的回复。我这里的问题是我不希望X被模板化。只有TaskPtr,我不确定这是否有意义。m_队列中的每个TaskPtr可能不同。要将任务放入std::shared_ptr
s的std::queue
,您应该从非模板Task\u base
派生Task
,然后将std:queue
放入std::shared_ptr
s的。不能使用异构类型的std::queue
。类X
不能包含无限多的成员,每个可能的类型t
都有一个成员。可以说,模板提供了编译时多态性。如果您需要运行时多态性,单靠模板是没有帮助的。它闻起来像std::any
@Evgeny如果您是正确的,它类似于std::any
,但是添加了execute()
。非常感谢您的深入回复。对于(起初)看起来如此简单的事情来说,这是一个多么复杂的解决方案啊。我很感谢你花时间写出来。@MichaelVeksler,更确切地说,std::any getValue()
;将动态类型代码移动到为动态类型设计的类型中。你的将TaskBase
的派生类与TaskBase
的实现联系在一起,还有其他一些缺点。@Yakk AdamNevraumont我考虑过,我相信使用std::any
的解决方案会更复杂,因为TaskBase
和Task
仍然需要执行execute()
。附加类型要么导致每次调用getValue()时动态分配,要么必须存储在某个位置,这可能会使执行变得复杂,或者需要重复数据。我不确定这是否值得。
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 ..
}
#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";
}