C++ 11では、すべてのコンテナの値の型がCopyConstructibleおよびAssignable(コンテナの特定の操作によってこれらの要件を課すことがありますが)であるという要件が削除されました。理論的には、これにより、たとえばstd::deque<const Foo>
を定義することが可能になります。これはC++ 03では不可能でした。「割り当て可能」とはどういう意味ですか?
私はこれを試したときに、予期せぬことにgcc 4.7.2が理解できないエラー[1]を吐き出しましたが、少なくともエラーを読みやすくし、libC++でclangをコンパイルしてエラーなしでコンパイルしました。
2つの異なるコンパイラが異なる結果を出すとき、私は正しい答えが何であるか疑問に思うので、const/assignable/value types/containersなどにあるすべての参照を検索します。 Gnu buganizerをはじめとするC++のメーリングリストの中には、SOに関するものや、他の場所にあるものがあります。基本的には以下のような対話として要約することができます。
Q:なぜ私は(簡単な例として)std::vector<const int>
を宣言することはできません
A:なぜ地球上であなたがそれをやりたいのでしょうか?それは無意味です。
Q:まあ、それは私には意味があります。なぜ私はそれをすることができないのですか?
A:標準では、値タイプを割り当てる必要があるためです。
質問:私はそれらを割り当てることを予定していません。私はそれらを作成した後、それらをconstにして欲しいです。
A:これは動作しません。次の問題!軽度の破線で
:
A2:C++ 11はそれを許可することを決定しました。あなたはただ待たなければなりません。その間、あなたのばかげたデザインを考え直してください。
これらは非常に説得力のある回答のようには見えませんが、おそらく私は「私には意味があります」というカテゴリに入るので、私は偏っています。私の場合は、スタックにプッシュされたものがポップされるまで不変であるというようなスタック状のコンテナを用意したいと思います。これは、タイプで表現できるようにするためには特に奇妙なことですシステム。
とにかく、「標準では、すべてのコンテナの値のタイプを割り当てる必要があります」という考えを開始しました。そして、私が見る限り、C++ 03標準のドラフトの古いコピーを見つけたので、それは本当です。それはしました。
一方、std::map
の値のタイプはstd::pair<const Key, T>
です。割り当て可能なようには見えません。それでも、私はstd::deque<std::tuple<const Foo>>
でもう一度試しました。そしてgccは目を打たずにコンパイルを進めました。だから私はいくつかの回避策があります。
は、その後、私はstd::is_assignable<const Foo, const Foo>
とstd::is_assignable<std::tuple<const Foo>, const std::tuple<const Foo>>
の値をプリントアウトしようとした、そしてあなたが期待するとして、それは、前者が割り当てられないと報告されていることが判明したが、後者は(打ち鳴らすとgccの両方によって)割り当て可能として報告されます。もちろん、それは本当に割り当て可能ではありません。 a = b;
をコンパイルしようとするとgccは苦情error: assignment of read-only location
で拒否されました(これは、このクエストで実際に分かりやすい唯一のエラーメッセージです)。しかし、割り当てを試みることなく、clangとgccの両方がdeque<const>
をインスタンス化するのと同じくらいうれしく、コードは正常に動作しているようです。
std::tuple<const int>
が本当に割り当て可能であれば、私はC++03
標準の矛盾については不平を言うことはできません - 本当に誰が気にしていますか?しかし、2つの異なる標準ライブラリの実装では、実際に、その参照を代入しようとすると(非常に賢明な)コンパイラエラーにつながる場合は、割り当て可能です。私はある時点でSFINAEのテンプレートでテストを使用したいと思うかもしれませんが、今日見たものに基づいて、それは非常に信頼できるものではありません。
質問に質問を出すことができる人がいます(タイトル内):割り当て可能とはどういう意味ですか?そして、2つのボーナス質問:
1)委員会は、本当にconst
値の型を持つコンテナをインスタンス化できるように、もしかして、または彼らは心の中でいくつかの他の非割り当て可能なケースがありましたか?、
2)は、実際にありますconst Foo
とstd::tuple<const Foo>
の間の重要な違いはありますか?
[1]本当に好奇心のために、ここでは(いくつかの行末を追加して、そしてあなたが十分スクロールダウンした場合の説明)std::deque<const std::string>
の宣言をコンパイルしようとしたときに、GCCによって生成されるエラーメッセージです。
In file included from /usr/include/x86_64-linux-gnu/c++/4.7/./bits/c++allocator.h:34:0,
from /usr/include/c++/4.7/bits/allocator.h:48,
from /usr/include/c++/4.7/string:43,
from /usr/include/c++/4.7/random:41,
from /usr/include/c++/4.7/bits/stl_algo.h:67,
from /usr/include/c++/4.7/algorithm:63,
from const_stack.cc:1:
/usr/include/c++/4.7/ext/new_allocator.h: In instantiation of ‘class __gnu_cxx::new_allocator<const std::basic_string<char> >’:
/usr/include/c++/4.7/bits/allocator.h:89:11: required from ‘class std::allocator<const std::basic_string<char> >’
/usr/include/c++/4.7/bits/stl_deque.h:489:61: required from ‘class std::_Deque_base<const std::basic_string<char>, std::allocator<const std::basic_string<char> > >’
/usr/include/c++/4.7/bits/stl_deque.h:728:11: required from ‘class std::deque<const std::basic_string<char> >’
const_stack.cc:112:27: required from here
/usr/include/c++/4.7/ext/new_allocator.h:83:7:
error: ‘const _Tp* __gnu_cxx::new_allocator< <template-parameter-1-1> >::address(
__gnu_cxx::new_allocator< <template-parameter-1-1> >::const_reference) const [
with _Tp = const std::basic_string<char>;
__gnu_cxx::new_allocator< <template-parameter-1-1> >::const_pointer =
const std::basic_string<char>*;
__gnu_cxx::new_allocator< <template-parameter-1-1> >::const_reference =
const std::basic_string<char>&]’ cannot be overloaded
/usr/include/c++/4.7/ext/new_allocator.h:79:7:
error: with ‘_Tp* __gnu_cxx::new_allocator< <template-parameter-1-1> >::address(
__gnu_cxx::new_allocator< <template-parameter-1-1> >::reference) const [
with _Tp = const std::basic_string<char>;
__gnu_cxx::new_allocator< <template-parameter-1-1> >::pointer = const std::basic_string<char>*;
__gnu_cxx::new_allocator< <template-parameter-1-1> >::reference = const std::basic_string<char>&]’
それでは、ここで起こっているのは、標準(§ 20.6.9.1)は、デフォルトのアロケータは、メンバ関数を持っていると主張しているということです。
pointer address(reference x) const noexcept;
const_pointer address(const_reference x) const noexcept;
const
テンプレート引数(明らかにUB)でインスタンス化すると、reference
とconst_reference
は同じ型であり、宣言が複製されます。定義の本体は、それが価値があるものと同じです。したがって、アロケータを認識できるコンテナは明示的にconst
の値の型を扱うことはできません。 const
をtuple
の内部に隠すと、アロケータがインスタンス化できます。標準からのこのアロケータ要件は、std::vector<const int>
の問題に関する少なくとも2つの古いlibstdC++バグをクローズするのを正当化するために使用されましたが、原理の固い点として私を攻撃しません。また、libC++は、重複した関数宣言を削除してallocator<const T>
の特殊化を提供するという、明らかな簡単な方法で問題を回避します。
IIRC割り当て可能な要件は削除されず、2つに分割されます(コピーおよび移動用) –
問題は、 'std :: deque'(またはシーケンス一般的にはコンテナ)ですが、 'std :: allocator'によって?代入可能な意味ではなく、 'const'型で動作するアロケータを使用しても問題ありません(' std :: allocator'は 'const'型では動作しません)? – jogojapan
@BenVoigt:それは本当になくなっています。以前は23.1(3)でした。「これらのコンポーネントに格納されているオブジェクトのタイプは、CopyConstructibleタイプ(20.1.3)の要件と、割り当て可能タイプの追加要件を満たす必要があります。その段落、次の段落、および関連するテーブル64(Assignableを参照)はすべて消えています。残りの要件は、コンテナでコピーコンストラクタまたはコピー代入を使用する場合、値タイプTがコンテナタイプXにCopyInsertableでなければならないということです。 – rici