2011-11-29 43 views
5

我有大量的類用於裝飾一些特定的方法。當裝飾方法減少樣板

是否有一種簡潔的方式來減少需要添加到每個類的樣板代碼量(主要是所有構造函數參數和成員來保存它們)?或者,更好的是,有沒有更好的方法來做到這一點?

我不能使用虛擬方法,只能使用gcc 4.6和vs2010支持的C++ 11功能的子集。

我相信C++ 11繼承構造函數在這裏會有所幫助,但是這兩種編譯器都不支持它們,我也沒有意識到解決方法。

以下是對這些類目前看起來像一個例子:

template<class Underlying, class T1> 
struct A : Base<A<Underlying, T1> > 
{ 
    typedef AImpl<decltype(declval<Underlying>().foo()), T1> impl; 
    A(Underlying u, T1 t1) : 
     u_(u), 
     t1_(t1) 
    {} 

    impl foo() const { return impl(u_.foo(), t1_); } 
    impl bar() const { return impl(u_.bar(), t1_); } 

    const Underlying u_; 
    T1 t1_; 
}; 


template<class Underlying, class T1, class T2> 
struct B : Base<B<Underlying, T1, T2> > 
{ 
    typedef BImpl<decltype(declval<Underlying>().bar()), T1, T2> impl; 
    B(Underlying u, T1 t1, T2 t2) : 
     u_(u), 
     t1_(t1), 
     t2_(t2) 
    {} 

    impl foo() const { return impl(u_.bar(), 999, t2_); } 
    impl bar() const { return impl(u_.foo(), t1_, t2_); } 

    const Underlying u_; 
    T1 t1_; 
    T2 t2; 
}; 

回答

1

你可以在GCC 4.6使用可變參數模板。

template<class Underlying, class... T> 
struct B : Base<B<Underlying, T...>> 
{ 
    typedef BImpl<decltype(declval<Underlying>().bar()), T...> impl; 

    template<typename V...> 
    B(Underlying u, V... v) : 
     u_(u), 
     t_(std::forward<V>(v)...) 
    {} 

    impl foo() const { return impl(u_.bar(), 999, std::get<1>(t_)); } // Not sure what the 999 is? 
    impl bar() const { return impl(u_.foo(), std::get<0>(t_), std::get<1>(t_)); } 

    const Underlying u_; 
    std::tuple<T...> t_; 
}; 
+0

但不是在VC++ 2010中...... – ildjarn

+0

我認爲在這裏使用'forward'可能有點不正確(至少效率低)。默認情況下,任何對'forward'的使用都應該在帶有推導參數類型的方法調用中。這意味着'template B(Underlying u,V && ... t):u_(u), t_(std :: forward (t)...) {}'。三件事:1)函數本身應該是一個模板。 2)參數應該被看作'U && ...',並且'向前'被使用。當前的代碼會將參數複製到B中,然後將它們移動到基類中。理想情況下,您需要零份副本,並在可能的情況下一路移動。 –

+1

有兩件事,在標準實現中它不是元組的成員(它在Boost中),並且在構造函數中使用forward是不正確的。應該是'template B(底層u,V && ... v):u_(u),t_(std :: forward (v)...){}'。 – DRayX

1

如果需要在vs2010中工作,那麼您最好的選擇是Boost.Preprocessor。它不像可變參數模板那樣強大,因爲它的最大遞歸深度爲3,最大迭代次數爲256,但它適用於每個帶有或不帶有C++ 11支持的編譯器。這些例子並不完全清楚你想要做什麼,但是如果你只是試圖裝飾函數,我使用以下(利用C++ 11用Boost.Preprocessor而不是可變模板完美轉發):

#define FORWARD(z, n, data) \ 
    ::std::forward<BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 0, data), n)> \ 
    (BOOST_PP_CAT(BOST_PP_TUPLE_ELEM(2, 1, data), n)) \ 
    /**/ 

//------------------------------------------------------------------------ 
// template<class R, class... A> 
// ::std::function<R(A...)> decorate(::std::function<R(A...)> const& func) 
// { 
//  return [func](A&&... a) -> R 
//  { 
//   /* DECORATOR STUFF */ 
//   return func(::std::forward<A>(a)...); 
//  }; 
// } 
//------------------------------------------------------------------------ 
#define MACRO(z, n, _) \ 
    template<class R BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, class A)> \ 
    ::std::function<R(BOOST_PP_ENUM_PARAMS_Z(z, n, a)> \ 
     decorate(::std::function<R(BOOST_PP_ENUM_PARAMS_Z(z, n, A))> const& func) \ 
    { \ 
     return [func](BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, &&a)) -> R \ 
     { \ 
      /* DECORATOR STUFF */ \ 
      return func(BOOST_PP_ENUM_ ## z(n, FORWARD, (A, a))); \ 
     }; \ 
    } \ 
    /**/ 

BOOST_PP_REPEAT(10, MACRO, ~) 

#undef MACRO 
#undef FORWARD 

如果你只是試圖綁定函數參數,那麼std::bind是你在找什麼。請注意,你可以用lambdas來完成這些任務,但裝飾器函數可以用來裝飾多個函數(當然lambda函數當然是一個offs),綁定對於綁定參數可能更簡潔一些(但是,lambda等效有時更易讀)。