代码之家  ›  专栏  ›  技术社区  ›  Greg Rogers

优雅的模板专业化

  •  4
  • Greg Rogers  · 技术社区  · 16 年前

    是否有一种优雅的方法可以根据模板参数之一对模板进行专门化?

    Ie。

    template<int N> struct Junk {
        static int foo() {
            // stuff
            return Junk<N - 1>::foo();
        }
    };
    
    // compile error: template argument '(size * 5)' involves template parameter(s)
    template<int N> struct Junk<N*5> {
        static int foo() {
            // stuff
            return N;
        }
    };
    
    template<> struct Junk<0> {
        static int foo() {
            // stuff
            return 0;
        }
    };
    

    也就是说,我正试图根据参数能被5整除来专门化一个模板。我似乎唯一能做到这一点的方法如下:

    template<int N> struct JunkDivisibleBy5 {
        static int foo() {
            // stuff
            return N;
        }
    };
    
    template<int N> struct Junk {
        static int foo() {
            // stuff
            if ((N - 1) % 5 == 0 && N != 1)
                return JunkDivisibleBy5<N - 1>::foo();
            else
                return Junk<N - 1>::foo();
        }
    };
    
    
    template<> struct Junk<0> {
        static int foo() {
            // stuff
            return 0;
        }
    };
    

    但这明显不够优雅,即使模板参数不需要实例化,也需要实例化所有模板。

    6 回复  |  直到 16 年前
        1
  •  13
  •   jwfearn    16 年前

    这是怎么回事:

    #include <iostream>
    using namespace std;
    
    template < typename T, T N, T D >
    struct fraction {
        typedef T value_type;
        static const value_type num = N;
        static const value_type denom = D;
        static const bool is_div = (num % denom == 0);
    };
    
    template< typename T, T N, T D, bool P >
    struct do_if {
        static void op() { cout << N << " NOT divisible by " << D << endl; }
    };
    
    template< typename T, T N, T D >
    struct do_if< T, N, D, true > {
        static void op() { cout << N << " divisible by " << D << endl; }
    };
    
    template < int N >
    void foo() {
        typedef fraction< int, N, 5 > f;
        do_if< typename f::value_type, f::num, f::denom, f::is_div >::op();
    }
    
    int main() {
        foo< -5 >();
        foo< -1 >();
        foo< 0 >();
        foo< 1 >();
        foo< 5 >();
        foo< 10000005 >();
        return 0;
    }
    
        2
  •  7
  •   Walter Bright    16 年前

    使用D编程语言模板,可以写成:

    struct Junk(int N)
    {
        static int foo()
        {
            static if (N == 0)
                return 0;
            else static if ((N % 5) == 0)
                return N;
            else
                return Junk!(N - 1).foo();
        }
    }
    

    静态if在编译时执行。

        3
  •  5
  •   Igor Semenov    16 年前

    所有计算都可以在编译时进行:

    #include <iostream>
    
    template<int N> struct Junk {
        enum { IsDivisibleBy5 = (N % 5 == 0) };
        template<bool D> struct JunkInternal {
            enum { Result = Junk<N-1>::Result };
        };
        template<> struct JunkInternal<true> {
            enum { Result = N };
        };
        enum { Result = JunkInternal<IsDivisibleBy5>::Result };
    };
    
    int main(int, char**)
    {
        std::cout << Junk< 0 >::Result << std::endl;
        std::cout << Junk< 7 >::Result << std::endl;
        std::cout << Junk< 10 >::Result << std::endl;
    
        return 0;
    }
    
        4
  •  4
  •   Johannes Schaub - litb    16 年前

    代码

    template<int A, bool = !(A % 5)>
    struct select : select<A-1> { };
    
    template<int A>
    struct select<A, true> { static int const value = A; };
    
    template<>
    struct select<0, true> { static int const value = 0; };
    
    int main() {
        std::cout << select<1>::value; // 0
        std::cout << select<7>::value; // 5
        std::cout << select<10>::value; // 10
    }
    

    保留除数变量

    template<int A, int D, bool = !(A % D)>
    struct select : select<A-1, D> { };
    
    template<int A, int D>
    struct select<A, D, true> { static int const value = A; };
    
    template<int D>
    struct select<0, D, true> { static int const value = 0; };
    
    int main() {
        std::cout << select<1, 3>::value; // 0
        std::cout << select<7, 3>::value; // 6
        std::cout << select<10, 3>::value; // 9
    }
    
        5
  •  2
  •   MSalters    16 年前

    继承非常有效:

    template<int N> struct Junk : private JunkBase < N % 5 > { };
    
    template<int N> struct JunkBase {
        static int foo() {
            // stuff
            return Junk<N - 1>::foo();
        }
    };
    template< > struct JunkBase<0> {
        static int foo() {
            return 0;
        }
    };
    

    如果你也需要N/5,你可能需要将N传递给JunkBase::foo。

        6
  •  0
  •   hark    16 年前

    我很难说它优雅,但这是我的代码版本,只使用模板进行计算(以及测试)--

    #include <iostream>
    
    template < int N > struct JunkDivBy5 {
        static int foo() {
            return N;
        }
    };
    
    template < int N > struct Junk {
        template < int N1 > struct _JunkCond {
            enum { val = ( N1 != 1 && ( N1 - 1 ) % 5 == 0 ) ? 1 : 0 };
        };
    
        template < int M, int N1 > struct _JunkBranch { /* Error */ };
    
        template < int N1 > struct _JunkBranch< 1, N1 > {
            typedef JunkDivBy5< N1 - 1 > Type;
        };
    
        template < int N1 > struct _JunkBranch< 0, N1 > {
            typedef Junk< N1 - 1 > Type;
        };
    
        static int foo() {
            return _JunkBranch< _JunkCond< N >::val, N >::Type::foo();
        }
    };
    
    template <> struct Junk< 0 > {
        static int foo() {
            return 0;
        }
    };
    
    int main( int argc, char *argv[] ) {
        std::cout << Junk< 0 >::foo() << std::endl;
        std::cout << Junk< 5 >::foo() << std::endl;
        std::cout << Junk< 7 >::foo() << std::endl;
        std::cout << Junk< 25 >::foo() << std::endl;
    }