2011-06-02 51 views
7

我正在創建一個模板化類D<N>,此方法返回不同的類型(根據N的值)(在這種情況下爲運算符())。代碼複製和模板專業化(當專用函數具有不同的返回類型時)

我只能通過創建兩個單獨的類聲明來完成這項工作,但這是以很多代碼重複爲代價的。我也試圖創建一個公共基類扔東西,常見到,但我不能讓構造繼承權,不知道怎麼地道,這將是,以及...

#include <cstdio> 

template <int N> 
struct D{ 
    int s; 
    D(int x):s(x){} 

    int yell(int x){ 
     printf("N=%d, %d\n", N, s+x); 
     return s+x; 
    } 

    D<N-1> operator()(int x){ 
     D<N-1> d(yell(x)); 
     return d; 
    } 
}; 

template <> 
struct D<1>{ 
    int s; 
    D(int x): s(x){} 

    int yell(int x){ 
     printf("N=%d, %d\n", 1, s+x); 
     return s+x; 
    } 

    int operator()(int x){ 
     return yell(x); 
    } 
}; 


int main() 
{ 
    D<2> f(42); 
    printf("%d\n", f(1)(2)); 
    return 0; 
} 

如何我可以讓我的代碼更好看嗎?

+0

你需要重新考慮返回類型取決於參數的值的效用。要麼使其成爲一致的多態返回類型,要麼找出總是返回基本類型的明智方式。在這種情況下,我通常會發現返回到應用程序的基本需求很有幫助。 – wallyk 2011-06-02 21:05:19

+0

問題是沒有一個好的類型來編碼一定長度的列表。做模板黑魔法將使我的小DSL可以很好地使用和類型安全。 – hugomg 2011-06-02 22:09:21

+0

所以你需要一些「編譯時間長度」鏈表?不是std :: array/boost :: array適合你的情況嗎?缺點是你不能從中獲取「子數組」對象,但你也可以使用「運行時變量長度接口」(迭代器,[],指針...)。 – ysdx 2011-06-03 06:51:35

回答

8

您可以使用奇怪的循環模板模式。

template<int N, template<int> typename D> struct d_inner { 
    D<N-1> operator()(int x) { 
     return D<N-1>(static_cast<D<N>*>(this)->yell(x)); 
    } 
}; 
template<template<int> typename D> struct d_inner<1, D> { 
    int operator()(int x) { 
     return static_cast<D<1>*>(this)->yell(x); 
    } 
}; 

template <int N> struct D : public d_inner<N, D> { 
    int s; 
    D(int x):s(x){} 

    int yell(int x){ 
     printf("N=%d, %d\n", N, s+x); 
     return s+x; 
    } 
}; 

不是說我看到這個特定對象的效用或目的是模板化的,它很可能不是。

+0

+1「不是說我看到這個特定對象的效用或目的是模板化的,它很可能不是」 – fedvasu 2013-09-18 17:22:03

4

我不知道它是更好看:但它避免了源代碼的重複:

// Find a name for this ... 
template<int N, template<int M> class X> 
struct foo { 
    typedef X<N> type; 
}; 
template< template<int M> class X > 
struct foo<0,X> { 
    typedef int type; 
}; 

template <int N> 
struct D{ 
    int s; 
    D(int x):s(x){} 

    int yell(int x){ 
    printf("N=%d, %d\n", N, s+x); 
     return s+x; 
    } 

    typename foo<N-1,D>::type 
    operator()(int x){ 
    return typename foo<N-1,D>::type(yell(x)); 
    } 
};