2016-08-18 19 views
8

Effective Modern C++の91ページの例を確認するのに手間がかかっていましたが、奇妙な問題のように思えました。このコードC++のnoexcept宣言がテンプレートの控除を変更します

template<typename C> 
void doStuff(C& a, C& b) noexcept(noexcept(doStuff(a.front(), b.front()))) { 
    std::cout << "container version" << std::endl; 
} 

template<> 
void doStuff<int>(int& x, int& y) noexcept { 
    std::cout << "int version" << std::endl; 
} 

int main() { 
    vector<int> v1 = {1, 2, 3}; 
    vector<int> v2 = {4, 5, 6}; 
    int x = 5; 
    int y = 6; 
    doStuff(x, y); 
    doStuff(v1, v2); 
} 

は私に

error: request for member ‘front’ in ‘a’, which is of non-class type ‘int’ void doStuff(C& a, C& b) noexcept(noexcept(doStuff(a.front(), b.front()))) {

だから、それは、doStuffのトップバージョンが呼び出されているように思えるにもかかわらず、a.front()とb.frontのようなエラーになります()する必要がありますintへの参照を返します。コードからすべてのnoexcept宣言を削除すると、期待される出力が得られます。

これはgcc 5.4です。

私は間違っていますか?

おかげ

+1

であなたの専門分野を置き換えテンプレートはcompile.time機能であることに注意してください。 'doStuff'関数の最初のバージョンが定義されているとき、コンパイラは' int'の特殊化について何も知らない。 –

+1

'doStuff'が' noexcept'仕様で最初に使われたときに宣言されていないという問題もあります。 – aschepler

答えて

7

問題があり、ときに、この時点で名前検索:

template<typename C> 
void doStuff(C& a, C& b) noexcept(noexcept(doStuff(a.front(), b.front()))) { 
//           ^^^^^^^ 

ちょうど1 doStuff()見つける:あなたの関数テンプレートを。専門化はまだ宣言されていないため、考慮されていません。

まず、特殊化を避けることです。彼らは厄介です。しかし、本当の修正は引数依存の参照目的のためだけに空の余分な型に固執することです。これは、インスタンス化されるまで呼び出しを遅らせますnoexcept検索に依存名を追加します。

namespace N { 
    struct adl { }; 

    void doStuff(adl, int& , int&) noexcept { 
     std::cout << "int version" << std::endl; 
    } 

    template<typename C> 
    void doStuff(adl, C& a, C& b) noexcept(noexcept(doStuff(adl{}, a.front(), b.front()))) { 
     std::cout << "container version" << std::endl; 
    } 
} 

template <class C> 
void doStuff(C& a, C& b) noexcept(noexcept(doStuff(N::adl{}, a, b))) 
{ 
    doStuff(N::adl{}, a, b); 
} 
+1

'int'オーバーロードは本当に最初になければなりませんか? 'noexcept'指定子の' doStuff'は依存シンボルではありません。つまり、インスタンス化されるまで解決されません。 – John

+0

おそらく驚くべきことに、これは 'C = std :: vector >'で失敗するでしょう。 – aschepler

+0

@aschepler修正されました。 – Barry

2

テンプレート特殊は過負荷ではありません。 doStuff<int>の専門はdoStuff<C>の過負荷ではなく、それは専門です。したがって、過負荷の解像度では考慮されませんが、テンプレートのインスタンス化では、オリジナルが過負荷解決によって選択されている場合、それを考慮します。過負荷(非テンプレート、2 int&秒を取る)

void doStuff(int& a, int& b) noexcept; 
関連する問題