2011-06-02 53 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)); 
    } 
};