2015-05-11 126 views
1

目标:使函数调度按预期工作。最小的示例代码应该说明问题。我想支持以下任务:命名任务,它们在自己的类中实现,以及使用lambda指定的更简单的任务。理想情况下,任何可以转换为std::function<void (void)>的应该可以工作。std :: enable_if和std :: shared_ptr

#include <iostream> 
#include <memory> 
#include <functional> 

// A Base class for my tasks                                                     
class BaseTask 
{ 
public: 
    virtual void blah() = 0; 
}; 

// An important enough tasks that it gets to have its                                               
// own class.                                                         
class NamedTask : public BaseTask 
{ 
public: 
    virtual void blah() 
    { 
    std::cout << "Hey !" << std::endl; 
    } 
}; 

// A wrapper around simpler tasks. (lambda)                                                  
class GenericTask : public BaseTask 
{ 
public: 
    GenericTask(const std::function<void (void)> fct) : 
    fct_(fct) {} 

    virtual void blah() override 
    { 
    fct_(); 
    } 

private: 
    std::function<void (void)> fct_; 
}; 

void enqueue(std::shared_ptr<BaseTask> t) 
{ 
    // store in queue.                                                       
    // We'll just call it here for the sake of the example                                              
    t->blah(); 
} 

template<typename Callable> 
//typename std::enable_if<!std::is_base_of<BaseTask, Callable>::value>::type                                         
//typename std::enable_if<!std::is_base_of<std::shared_ptr<BaseTask>, Callable>::value>::type                                     
void enqueue(const Callable &c) 
{ 
    auto t = std::make_shared<GenericTask>(c); 
    t->blah(); 
} 

int main() 
{ 
    auto named = std::make_shared<NamedTask>(); 
    enqueue(named); // doesn't compile: tries to call the templated enqueue.                                         

    enqueue([]() -> bool { std::cout << "Lamda" << std::endl; }); 
} 

问题:我不管理编写正确的enable_if模板。示例中的注释行是我所尝试的。

  • 第一个不起作用,因为赎回是std::shared_ptr<NamedTask>类型,这是不是BaseTask的孩子。
  • 第二个也失败了,大概是因为std::shared_ptr<NamedTask>不是来自std::shared_ptr<BaseTask>

回答

3

你有两种情况:您的调用是转换shared_ptr<BaseTask>,还是不行。检查基地是不正确的,因为shared_ptr<NamedTask>与类层次结构不相关shared_ptr<BaseTask>,但你可以从它构造shared_ptr<BaseTask>

即:

// is convertible to shared_ptr<BaseTask> 
void enqueue(std::shared_ptr<BaseTask> t); 

// is NOT convertible to shared_ptr<BaseTask> 
template<typename Callable> 
typename std::enable_if< 
    !std::is_convertible<Callable, std::shared_ptr<BaseTask>>::value 
>::type 
enqueue(const Callable &c); 

或者,你能想到的两种情况constructible /不constructible:

template<typename Callable> 
typename std::enable_if< 
    !std::is_constructible<std::shared_ptr<BaseTask>, Callable>::value 
>::type 
enqueue(const Callable &c); 

第三种方法是调理功能模板enqueue上任何可调用与零参数:

template<typename Callable> 
auto enqueue(const Callable &c) -> decltype(c(), void()) 
+0

我不知道'std :: is_convertible'。这正是我所期待的。感谢您提供可行的选择。 – Xaqq

相关问题