2014-01-10 23 views
1

考慮下面的代碼:如何使用Boost MPL在函數中有多個返回點?

struct Param {}; 
struct Base { 
     virtual char f(Param const &) const = 0; 
}; 
struct A : Base { 
     explicit A(Param const &) {} 
     virtual char f(Param const &) const {return 'A';} 
}; 
struct B : Base { 
     explicit B(Param const &) {} 
     virtual char f(Param const &) const {return 'B';} 
}; 
struct C : Base { 
     explicit C(Param const &) {} 
     virtual char f(Param const &) const {return 'C';} 
}; 

char my_function(Param const & param, Base const & base) 
{ 
     if(A const * const p = dynamic_cast<A const *>(&base)) { 
       return p->f(param); 
     } 
     if(B const * const p = dynamic_cast<B const *>(&base)) { 
       return p->f(param); 
     } 
     if(C const * const p = dynamic_cast<C const *>(&base)) { 
       return p->f(param); 
     } 
     return '0'; 
} 

然後如果我寫

Param x, y; 
std::cout << my_function(x, B(y)) << std::endl; 

它輸出B

我的目標是更改my_function的實現,以便它可以支持在編譯時定義的一組子類型Base。在這裏,我手寫了我將爲{A, B, C}類型獲得的擴展代碼。 我想模板化my_function有一組類型,並調用它是這樣的:

std::cout << my_function<boost::mpl::set<A, B, C> >(x, B(y)) << std::endl; 

輸出B,或者,如:

std::cout << my_function<boost::mpl::set<A, C> >(x, B(y)) << std::endl; 

輸出0

我不知道使用哪個MPL構造來實現此結果。

我最初以爲find_if一個電話可以讓找到集合到base可以dynamic_casted第一類,但實際上這個算法,最喜歡的MPL算法,靜態顯然產生了效果,因此不能與運行時參數一起使用(base)。

分類爲「運行時」的唯一MPL算法是for_each,但我無法弄清楚如何使用它來產生與我的多重返回語句相同的效果(我甚至不知道它是否是它是可能的)。 感謝任何能幫助我的MPL演講者。

PS:不要告訴我,我應該避免動態蒙上或我可以簡單地

char my_function(Param const & param, Base const & base) {return base.f(param);} 

我簡單跟我現實生活中的問題相比,代碼示例,我不能改變現有的設計。

回答

2

像這樣的東西應該工作:

struct functor 
{ 
    public: 
    functor(Param const & param, Base const & base) 
    : param_(param), 
    base_(base), 
    found_(false) 
    { 
    } 

    template<typename Child> 
    void operator()(Child*) 
    { 
    if (!found_) 
    { 
     if(Child const * const p = dynamic_cast<Child const *>(&base_)) 
     { 
     value_ = p->f(param_); 
     found_ = true; 
     } 
    } 
    } 

    char get_value() 
    { 
    return value_; 
    } 

    private: 
    Param const & param_; 
    Base const & base_; 
    bool found_; 
    char value_; 
}; 

template <typename ...Types> 
char my_function(Param const & param, Base const & base) 
{ 
    typedef boost::mpl::vector<Types...>::type children; 

    functor f(param, base); 

    boost::mpl::for_each<children>(std::ref(f)); 

    return f.get_value(); 
} 

int main() 
{ 
    Param x, y; 
    std::cout << my_function<A*, B*, C*>(x, B(y)) << std::endl; 

    return 0; 
} 
+0

謝謝你的回答。您的解決方案的缺點是每次都會遍歷整個類型列表,但它很好地展示瞭如何使用MPL for_each。同時,我找到了我發佈的解決方案(不使用MPL算法)。 –

1

這裏是我已經找到了解決辦法。

namespace detail { 

template <typename First, typename Last> 
struct my_function_impl { 
     static char apply(Param const & param, Base const & base) 
     { 
       BOOST_MPL_ASSERT_NOT((boost::is_same<First, Last>)); 
       typedef typename boost::mpl::deref<First>::type Child; 
       BOOST_MPL_ASSERT((boost::is_base_of<Base, Child>)); 
       if(Child const * const p = dynamic_cast<Child const *>(&base)) { 
         return p->f(param); 
       } 
       typedef typename boost::mpl::next<First>::type Next; 
       return my_function_impl<Next, Last>::apply(param, base); 
     } 
}; 

template <typename It> 
struct my_function_impl<It, It> { 
     static char apply(Param const &, Base const &) 
     { 
       return '0'; 
     } 
}; 

} // namespace detail 

template <typename ContainerOfTypes> 
char my_function(Param const & param, Base const & base) 
{ 
     typedef typename boost::mpl::begin<ContainerOfTypes>::type Begin; 
     typedef typename boost::mpl::end<ContainerOfTypes>::type End; 
     return detail::my_function_impl<Begin, End>::apply(param, base); 
} 

和呼叫:

std::cout << my_function<boost::mpl::set<A, B, so::Base> >(x, C(y)) << std::endl; 

任何的簡化或改進建議是值得歡迎的。