11

次のコードは、gcc 4.7.2(mingw)で正常にコンパイルされます。

#include <unordered_map>
#include <tuple>

struct test
{
        test() =default;
    private:
        test(test const&) =delete;
};

int main()
{
    std::unordered_map<char, test> map;

    map.emplace(
        std::piecewise_construct,
        std::forward_as_tuple('a'),
        std::forward_as_tuple()
    );
}

ただし、コピーコンストラクターをtestからtest(test const&) =delete;に変更するtest(test const&) =default;と、テンプレートエラーの嘔吐はconst test&に変換できないことについて文句を言うようです(ここtestにテキストがあります)。どちらも機能しないのですか?または、そうでない場合は、両方ともエラーを発生させるべきではありませんか?

4

2 に答える 2

12

テンプレートエラーの嘔吐をもっと注意深く見ると、このニンジンの塊がその中にあることがわかります。

test.exe.cpp:8:3: error: 'constexpr test::test(const test&)' is private

これが問題の手がかりです。

GCC 4.7.2は、テンプレート引数の推論の一部としてアクセスチェックを行いません(C ++ 03で必要とされたように)。is_convertible特性は、テンプレート引数の推論に依存するSFINAEを使用して実装され、過負荷解決がプライベートコンストラクター引数を選択する場合推論は成功しますが、選択したコンストラクターがプライベートであるため、アクセスチェックは失敗します。これはGCC4.7の問題です。これは、14.8.2[temp.deduct]の新しいC++11ルールに従うように変更されていないためです。

-8-置換によって無効な型または式が生成された場合、型の推定は失敗します。無効な型または式は、置換された引数を使用して記述された場合に不正な形式になるものです。[注:アクセスチェックは、置換プロセスの一部として実行されます。—エンドノート]

これは以前の控除規則に対する大きな変更であり、以前その段落は述べていました

-8-置換によって無効な型または式が生成された場合、型の推定は失敗します。無効な型または式は、置換された引数を使用して記述された場合に不正な形式になるものです。アクセスチェックは、置換プロセスの一部としては実行されません。したがって、推論が成功した場合でも、関数がインスタンス化されたときにアクセスエラーが発生する可能性があります。

この変更は、DR1170によってC++ 0xプロセスのかなり遅い段階で行われ C++11でSFINAEを完全に素晴らしいものにします:)

GCC 4.8は新しいルールを実装しているためis_convertible、同様の特性により、アクセスできないコンストラクターに対して正しい答えが得られます。

于 2013-02-12T16:18:33.637 に答える
4

正解はJonathanWakeleyのものです。に関連する同様の問題を抱えている人々に役立つ情報を提供するので、これは残しておきますinsert


短いバージョンでは、これはGCC 4.7.2で使用されている標準ライブラリの実装の問題が原因で発生します。これは、C++11標準で使用されている誤解を招く表現に起因しています。表現の変更提案と、GCC4.8の実装の修正があります。


ロングバージョン

このGCCバグエントリinsertは、の代わりに使用される非常によく似た問題を報告しemplaceます。のlibstdc++実装は、関数(具体的には)insertについて述べている標準に従います。inserttemplate <class P> pair<iterator,bool> insert(P&& obj)

(§23.5.4.4/ 5)備考:Pが暗黙的にに変換可能でない限り、この署名は過負荷解決に参加してはなりませんvalue_type

libstdc ++は、関連するタイプenable_ifをチェックするステートメントを使用してこの要件を実装したようです。std::is_convertible<>

上でリンクされたバグレポートは、実際std::is_constructible<>に使用されるべきであり、標準の表現を変更する必要があると述べています。これは、すでにこの標準への変更を提案しているLWG(言語ワーキンググループ)の問題にリンクしています(LWG問題#2005Portland 2012エントリ、以下の提案された変更の関連部分を参照)。

  1. pの周りの23.5.4.4[unord.map.modifers]を変更します。示されているように1:

    template <class P>
    pair<iterator, bool> insert(P&& obj);
    

[...]備考:Pが暗黙的にvalue_typeに変換可能でstd::is_constructible<value_type, P&&>::valueない限り、この署名は過負荷解決に関与しません。

提案された変更はまた、insert上記の機能の効果はの効果と同等でなければならないと述べていemplace(std::forward<P>(obj))ます。したがって、あなたの質問で説明されている問題はまったく同じ問題であると言って間違いないでしょう。

実際、提案された変更は最近のGCC4.8スナップショットに反映されているようです。GCC4.8でコードをコンパイルすると、is_convertibleチェックは実行されず、エラーメッセージは表示されません。

于 2013-02-11T09:50:22.337 に答える