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";   
}