0

什麼是C++關於模板特化和命名空間限定的規則?我有一些代碼可以歸結爲以下的代碼,這讓我意識到我不瞭解C++有關模板特化初始化的規則。對我來說這似乎很奇怪,g::F<>的專業化甚至允許在h之內,但是,考慮到這一點,我不知道爲什麼事情會按照他們的方式行事。模板專門化/初始化和命名空間?

namespace g { 

    struct N { 
    N(char c):c_(c){} 
    char c_; 
    }; 

    template <typename V> 
    struct F { 
    static N n_s; // <-- want to initialize these for specializations 
    }; 

    namespace h { 
    struct X { static constexpr char k{'x'}; }; 

    template <> N F<char>::n_s{h::X::k}; // OK 
    template <> N F<int>::n_s{X::k};  // fails on "‘X’ not declared" 
    } 
} // namespace g 

// Seems weirdest to me. N and F need full qualifications but X doesn't. 
template <> g::N g::F<float>::n_s{h::X::k}; // OK also! 

最後的實例化/初始化,模板靜態成員的初始推斷g命名空間,使得它看起來就像模板充當雖然,就好像是位於同一地點的代碼作爲初始化行爲模板定義本身。

該規範的規定是什麼規定了這種行爲? (請注意,這是對GCC 4.8.1測試,看起來迄今有點像一個bug ......)

回答

-1

在:

template <> N F<int>::n_s{X::k};  // fails on "‘X’ not declared" 

它失敗,因爲與F<int>::n_s相關的命名空間是g,而Xg::h中聲明。這就是爲什麼你需要把它拼出來,如h::F<int>::n_s

+0

呵呵?你的意思是拼出來像g :: F :: n_s?我可以清楚地看到,它必須像使用命名空間g一樣被限定,不管它在哪裏使用,但我不明白爲什麼在h中允許初始化,或者爲什麼要在f中使用F :: n_s {h :: X :: k}初始化允許在g之外,而不需要額外的g :: qualifier ... – Jeff

2

這裏關鍵的困惑不在於專業化,而在於資質。讓我們來看看最後的專業化(在全局命名空間)來說明這一點:

template <> g::N g::F<float>::n_s{h::X::k}; 

當行開始,你在全局命名空間。因此,g::N必須是合格的,g::F<float>也是如此。

但是,當你經過你專門研究的事物(即在n_s之後)時,你現在處於你正在專精的範圍內,即在g::F之內。所有進一步查詢均在此範圍內完成,因此x必須被認定爲h::X。儘管它允許在包含原始名稱空間的名稱空間中專門化事物,但專門研究嵌套名稱空間(在您的案例中爲h)對我來說看起來很奇怪,但是標準在這裏稍微含糊不清,正如它在14.7.3/2:「明確的專門化應在包含專門模板的命名空間中聲明。」

全局命名空間包含F,所以很好,正如g一樣。 h沒有包含F,但是hg之內,所以專業化也在g之內,這在技術上使這很好。然而,通過這個推理,你可以絕對無處不在的專門化一個模板,因爲你總是在全局命名空間裏面,它包含了所有的東西。所以我很確定GCC在這裏的行爲過於寬容,並且存在一個bug。您應該嘗試與其他編譯器一起使用,然後提交錯誤報告,或者根據標準提交缺陷報告。

+0

謝謝,這是我所懷疑的,但是我在閱讀規範時找不到直接的矛盾。我試圖將一個像F這樣的模板混入到像h這樣的嵌套命名空間中,當我將它蒸餾到上面最簡單的情況/行爲時。 – Jeff