2015-05-11 177 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

相關問題