2012-04-26 127 views
1

我非常希望能夠提供仿函數作爲模板參數。函數必須能夠提供「自己」作爲該論證。模板仿函數必須提供自己作爲模板參數

我想是這樣的:

template<typename T, template<typename> class SumFunctor> class foo; 

template<typename T> 
struct sum_default 
{ 
    foo<T, sum_default> operator()(foo<T, sum_default> a, foo<T, sum_default> b) const 
    { 
      T a_data = a.data(); 
      T b_data = b.data(); 
      return foo<T, sum_default>(a_data + b_data); 
    } 
}; 

template<typename T> 
struct sum_awesome 
{ 
    foo<T, sum_awesome> operator()(foo<T, sum_awesome> a, foo<T, sum_awesome> b) const 
    { 
      T a_data = a.data(); 
      T b_data = b.data(); 
      return foo<T, sum_awesome>(a_data - b_data); 
    } 
}; 

template<typename T=int, template<typename> class SumFunctor=sum_default> 
class foo 
{ 
private: 
    T _data; 
    SumFunctor<T> _functor; 
public: 
    foo<T, SumFunctor>(T data) : _data(data) {} 

    T data() { return _data; } 

    friend const foo operator +(const foo& lhs, const foo& rhs) 
    { 
      return lhs._functor(lhs,rhs); 
    } 
}; 

int main(){ 
    foo<> a(42); 
    foo<double> b(1.0); 
    foo<double,sum_default> c(4.0); 
    foo<double,sum_awesome> d(4.0); 

    a+a; 
    d+d; 
} 

這是可能的,如果是這樣,怎麼樣?

另一種解決方案是爲構造函數提供函子,但是我認爲這非常難看,因爲用戶必須自己動態地分配函數(因爲我們無法確定構造函數中的函數的類型。這樣做似乎也有點難看):

foo<double> a(42, new sum_default<double>()); 

這也迫使從一些預先定義的基本算符派生的所有仿函數。

UPDATE

試圖模板參數添加到sum_default模板參數沒有出現要解決的問題:

template<typename T> 
struct sum_default 
{ 
// Error 1 error C3200: 'sum_default<T>' : invalid template argument for template parameter 'SumFunctor', expected a class template 
foo<T, sum_default<T> > operator()(foo<T, sum_default<T> > a, foo<T, sum_default<T> > b) const 
{ 
    T a_data = a.data(); 
    T b_data = b.data(); 
    return foo<T, sum_default<T> >(a_data + b_data); 
} 
}; 
+0

謝謝您迴應,但你所建議的不會編譯。 – user1202032 2012-04-26 18:22:19

+0

好的。我在問題中添加了錯誤。如果您可以提供關於如何解決我的定義順序的幫助,將會大大受益。 – user1202032 2012-04-26 18:30:44

+0

對不起,我最初誤解了你的代碼的意圖。對不起,噪音。 : - ] – ildjarn 2012-04-26 18:40:12

回答

3

什麼咬你在這裏被稱爲「類名稱注射」 –內的類模板,例如Foo<T>,不合格使用Foo實際上視爲Foo<T>。引用C++ 11§14.6.1/ 1:

與正常(非模板)類相似,類模板具有注入類名。注入的類名稱可以用作模板名稱類型名稱。當它被用來與模板參數列表,作爲模板參數爲模板模板參數,或如在最終標識符闡述型說明符朋友類模板聲明的它指的是類模板本身。否則,它相當於模板名稱後面跟着模板參數,該模板參數包含在<>中的類模板中。

因此,中sum_default<T>裏面,當你有foo<T, sum_default>,它會被視爲雖然您鍵入foo<T, sum_default<T> >(其爲foo想要一個模板的模板參數顯然不會工作)。

爲了避免這種情況,您需要限定這些類模板中類模板名稱的用法。因爲你的類模板是在全球範圍內,::足夠:

template<typename T> 
struct sum_default; 

template<typename T = int, template<typename> class SumFunctor = sum_default> 
class foo 
{ 
    T _data; 
    SumFunctor<T> _functor; 

public: 
    foo<T, SumFunctor>(T data) : _data(data) { } 

    T data() { return _data; } const 

    friend foo operator +(foo const& lhs, foo const& rhs) 
    { 
     return lhs._functor(lhs, rhs); 
    } 
}; 

template<typename T> 
struct sum_default 
{ 
    foo<T, ::sum_default> operator()(foo<T, ::sum_default> a, 
             foo<T, ::sum_default> b) const 
    { 
     return foo<T, ::sum_default>(a.data() + b.data()); 
    } 
}; 

template<typename T> 
struct sum_awesome 
{ 
    foo<T, ::sum_awesome> operator()(foo<T, ::sum_awesome> a, 
            foo<T, ::sum_awesome> b) const 
    { 
     return foo<T, ::sum_awesome>(a.data() - b.data()); 
    } 
}; 

int main() 
{ 
    foo<> a(42); 
    foo<double> b(1.0); 
    foo<double, sum_default> c(4.0); 
    foo<double, sum_awesome> d(4.0); 

    a + a; 
    d + d; 
} 

注意,這也可以讓你正是如此定義foo的構造,降低噪音位:

foo(T data) : _data(data) { } 
+0

很有意思,謝謝! – user1202032 2012-04-26 18:49:45