2017-07-08 34 views
6

此示例代碼:C++模板遞歸雙鏈表誤差GCC(但鐺++接受)

#include <string> 
#include <iostream> 

template <int i> 
struct Wrapper 
{ 
    static const std::string _str; 
    typedef const Wrapper<i+1> NextType_t; // template recursion 
    static NextType_t _nxt; 
    typedef const Wrapper<i-1> PrevType_t; // template recursion 
    static PrevType_t _prev; 
}; 

template<int i> 
const std::string Wrapper<i>::_str = std::to_string(i); 

template<int i> 
typename Wrapper<i>::NextType_t Wrapper<i>::_nxt; 

template<int i> 
typename Wrapper<i>::PrevType_t Wrapper<i>::_prev; 


// recursion termination - lower bound 
template <> 
struct Wrapper<-1> 
{ 
     static const std::string _str; 
     typedef const Wrapper<0> NextType_t; 
     static NextType_t _nxt; 
     typedef const Wrapper<-1> PrevType_t; 
     static PrevType_t _prev; 
}; 

const std::string Wrapper<-1>::_str = std::to_string(-1); 

typename Wrapper<-1>::NextType_t Wrapper<-1>::_nxt; 
typename Wrapper<-1>::PrevType_t Wrapper<-1>::_prev; 

// recursion termination - upper bound 
template <> 
struct Wrapper<UPPER_LIMIT> 
{ 
    static const std::string _str; 
    typedef const Wrapper<-1> NextType_t; 
    static NextType_t _nxt; 
    typedef const Wrapper<UPPER_LIMIT-1> PrevType_t; 
    static PrevType_t _prev; 
}; 

const std::string Wrapper<UPPER_LIMIT>::_str = std::to_string(UPPER_LIMIT); 

typename Wrapper<UPPER_LIMIT>::NextType_t Wrapper<UPPER_LIMIT>::_nxt; 
typename Wrapper<UPPER_LIMIT>::PrevType_t Wrapper<UPPER_LIMIT>::_prev; 


int 
main(
    int argc, 
    char **) 
{ 
    Wrapper<0> wrapperFirst; 
    Wrapper<UPPER_LIMIT> wrapperLast; 

    // here's the list 
    std::cout << wrapperFirst._str << std::endl; 
    std::cout << wrapperFirst._nxt._str << std::endl; 
    std::cout << wrapperFirst._nxt._nxt._str << std::endl; 
    // [...] 

    // and the final element 
    std::cout << wrapperLast._str << std::endl; 
    std::cout << wrapperLast._prev._str << std::endl; 
    std::cout << wrapperLast._prev._prev._str << std::endl; 
    // [...] 

    // and the tailing NIL 
    std::cout << Wrapper<UPPER_LIMIT>::NextType_t::_str << std::endl; 

    return 0; 
} 

失敗對於GCC:

> g++ -std=c++11 -DUPPER_LIMIT=100 -ftemplate-depth=500 -o test main.cpp 
main.cpp: In instantiation of ‘struct Wrapper<499>’: 
main.cpp:24:33: recursively required from ‘struct Wrapper<1>’ 
main.cpp:24:33: required from ‘struct Wrapper<0>’ 
main.cpp:43:47: required from here 
main.cpp:24:33: fatal error: template instantiation depth exceeds maximum of 500 (use -ftemplate-depth= to increase the maximum) 
typename Wrapper<i>::NextType_t Wrapper<i>::_nxt; 
          ^~~~~~~~~~ 
compilation terminated. 

但成功用於鐺:

> clang++ -std=c++11 -DUPPER_LIMIT=100 -ftemplate-depth=500 -o test main.cpp 
> ./test 
0 
1 
2 
100 
99 
98 
-1 

代碼中有錯嗎?我不知道海灣合作委員會想超越UPPER_LIMIT,因爲有一個終止專業化。

+2

可能是因爲您在定義「Wrapper 」專業化之前爲'Wrapper <-1>'定義了靜態成員變量。如果你定義了所有的'Wrapper'結構,那麼會發生什麼?然後是這些類的靜態結構? – 1201ProgramAlarm

+0

@ 1201ProgramAlarm你在正確的軌道上,但它是靜態成員的*定義*,而不是他們的聲明導致問題(可能) – Frank

+0

謝謝! - 對你們雙方都有同樣的意見,回答如下 –

回答

4

Wrapper<-1>被實例化該線路上

typename Wrapper<-1>::NextType_t Wrapper<-1>::_nxt; 

這導致Wrapper<0>被實例化,這會導致Wrapper<1>被實例化,等等。在代碼中的這一點上,對於Wrapper<UPPER_LIMIT>專業化尚未定義,所以這會導致無限遞歸。

Wrapper<UPPER_LIMIT>專業化的定義移動到Wrapper<-1>::_nxt定義之上解決了該問題。

顯然Clang推遲實例化,以避免出現此問題。

+0

非常感謝! 我也將類聲明分隔爲* .h –