コンテナーの要件がC++ 03からC++ 11に変更されました。 C++ 03には包括的な要件(たとえば、ベクターのコピー構築可能性および割り当て可能性)がありましたが、C++ 11には、各コンテナー操作に関する細かい要件が定義されています(セクション23.2)。
その結果、たとえば、割り当てを必要としない特定の操作(構築とPush_back
はそのような操作です。 insert
はありません)。
私が不思議に思っているのは、これは標準がvector<const T>
?理由がわからない-const T
は、constメンバーを持つ構造体と同じように、コピー構築可能で割り当て可能ではない型ですが、何かを見落としている可能性があります。
(私が何かを見逃したかもしれないと私に思わせるものの一部は、インスタンス化しようとするとgccトランクがクラッシュして燃えるということですvector<const T>
、ただしvector<T>
Tにはconstメンバーがあります)。
いいえ、アロケータの要件では、Tは「非const、非参照オブジェクトタイプ」になる可能性があると言われています。
定数オブジェクトのベクトルでは、多くのことはできません。そして、_const vector<T>
_はとにかくほとんど同じです。
何年も経った今でも、この汚い回答はコメントや投票を集めているようです。常に稼働しているわけではありません。 :-)
適切な参照を追加するには:
私が紙に書いているC++ 03標準の場合、セクション[lib.allocator.requirements]の表31は次のように述べています。
_
T, U any type
_
そのanyタイプが実際に機能したわけではありません。
したがって、次の標準であるC++ 11は、[allocator.requirements]で クローズドラフト と次の表27を示しています。
_
T, U, C any non-const, non-reference object type
_
これは、私が最初に上記でメモリから書いたものに非常に近いものです。これはまた、質問の内容でもあります。
ただし、C++ 14では( ドラフトN4296 )表27に次のように記載されています。
_
T, U, C any non-const object type
_
おそらく、参照がおそらくオブジェクト型ではないためでしょうか?
そして今C++ 17( ドラフトN4659 )では、表30で次のように述べています。
T, U, C any cv-unqualified object type (6.9)
したがって、const
だけでなく、volatile
も除外されます。とにかく古いニュースだと思います。
Howard Hinnantの直接の情報 も参照してください。現在はすぐ下にあります。
更新
受け入れられた(そして正しい)答えの下で、私は2011年にコメントしました:
結論:
const T
を保持するコンテナは設計していません。私はそれを少し考えましたが。そして、私たちは偶然にそれを行うことに本当に近づきました。私の知る限り、現在のこだわりは、デフォルトのアロケータのオーバーロードされたaddress
メンバー関数のペアです:T
がconst
の場合、これらの2つのオーバーロードは同じです署名。これを修正する簡単な方法は、std::allocator<const T>
を特殊化し、オーバーロードの1つを削除することです。
次のC++ 17ドラフトでは、vector<const T>
が合法化されたように見え、偶然にも実行したと思います。 :-)
P0174Raddress
オーバーロードをstd::allocator<T>
から削除します。 P0174R は、その根拠の一部としてのstd::allocator<const T>
のサポートについて言及していません。
修正
以下のコメントでaddress
オーバーロードは非推奨であり、削除されないことに注意してください。私の悪い。非推奨のメンバーは、20.10.9ではstd::allocator
が定義されている場所には表示されませんが、代わりにセクションD.9に降格されます。私がこれを投稿したとき、私はこの可能性について第D章をスキャンすることを怠っていました。
T.C.ありがとう修正のため。私はこの誤解を招く答えを削除することを考えましたが、おそらく私が行ったのと同じように他の誰かが仕様を読み違えるのを防ぐために、この修正を残しておくのが最善です。
これについては非常に良い答えがすでにありますが、何ができるか、何ができないかを示すために、より実践的な答えを出すことにしました。
したがって、これは機能しません:
vector<const T> vec;
理由を理解するには、他の回答を読んでください。そして、ご想像のとおり、これも機能しません。
vector<const shared_ptr<T>> vec;
T
はconst
ではなくなりましたが、vector
はT
sではなくshared_ptr
sを保持しています。
一方、これはdoes動作します:
vector<const T *> vec;
vector<T const *> vec; // the same as above
ただし、この場合、constはポインターが指しているオブジェクトであり、ポインター自体ではありません(ベクターが格納するものです)。これは次と同等です。
vector<shared_ptr<const T>> vec;
結構です。
ただし、式の最後にconst
を置くと、ポインターがconst
に変わるため、次のコードはコンパイルされません。
vector<T * const> vec;
少しわかりにくいかもしれませんが、あなたはそれに慣れています。
他の答えを補完する、別のアプローチは、使用することです:
vector<unique_ptr<const T>> vec;
vec
のみがアイテムの所有権を持つことを強制したい場合です。または、アイテムをvec
に動的に移動し、ある時点でそれらを外部に移動したい場合。
指摘したように、ポインタconst
セマンティクスは混乱するかもしれませんが、shared_ptr
およびunique_ptr
ではありません。 const unique_ptr<T>
はconstポインターであり、unique_ptr<const T>
は、予想どおりconst pointeeです。