可変長引数をとることができるコンストラクタが必要な場合、可変テンプレート-またはstd::initializer_list
のどちらを使用するかをC++ 11の現在の状態(gcc 4.7.2など)でどのように選択する必要がありますか?コンストラクタの場合、variadic-templatesとstd :: initializer_listのどちらを選択すればよいですか?
答えて
バリデーショナルテンプレートを使用すると、さまざまなタイプの引数を指定できますが、std::initializer_list
には引数の型がテンプレート化されています。これは、リスト内のすべての要素の型が同じでなければならないことを意味します(または、基になる型に変換できますが、変換を狭めることはできません)。これが望ましいかどうかによって、どちらか一方を選択することができます。
同様のタイプの控除がinitializer_list
のために実行することはできませんしながら、構文形式T&&
は、左辺値参照と右辺値参照の両方に結合することができるという点で、あなたは、完璧な転送を必要とする場合にも、可変長引数テンプレートは通常、デフォルトの選択である:
struct A
{
// Deduces T& for lvalue references, T for rvalue references, and binds to both
template<typename... Ts>
A(Ts&&...) { }
// This is an rvalue reference to an initializer_list. The above type deduction
// does not apply here
template<typename T>
A(initializer_list<T>&&) { }
};
はまた、あなたが均一な初期化構文(つまり、中括弧)を使用する場合initializer_list
を受け入れるコンストラクタが別の実行可能なコンストラクタが存在していても、デフォルトで呼び出されることに、気づきます。
struct A
{
A(int i) { }
};
struct B
{
B(int) { }
B(std::initializer_list<A>) { }
};
int main()
{
B b {1}; // Will invoke the constructor accepting initializer_list
}
完璧な転送に関するビットを拡張すると、 'std :: initializer_list
@LucDanton:良い点。 –
私は可変引数テンプレートを択一常にをお勧めしますし、可能な限りstd::initializer_list
を避ける:これは、またはあなたが持っているしたい何かあってもなくてもよいです。
これは私がC++ 11とstd::vector
を実装しているだろうかです:、main
に示したような理由がある
#include <iostream>
#include <vector>
struct exp_sequence {
template <typename... T>
exp_sequence(T&&...) {}
};
struct from_arglist_t {} from_arglist;
template <typename T>
class my_vector {
std::vector<T> data;
public:
my_vector(int n, T const& e) : data(n, e) {}
template <typename... Args>
my_vector(from_arglist_t, Args&&... args) {
data.reserve(sizeof...(Args));
exp_sequence{(data.push_back(std::forward<Args>(args)),1)...};
}
std::size_t size() { return data.size(); }
};
int main()
{
std::vector<int> v1{13, 13}; std::cout << v1.size() << '\n'; // 2
std::vector<int> v2(13, 13); std::cout << v2.size() << '\n'; // 13
my_vector<int> v3{13, 13}; std::cout << v3.size() << '\n'; // 13
my_vector<int> v4(13, 13); std::cout << v4.size() << '\n'; // 13
my_vector<int> v5(from_arglist, 13, 13); std::cout << v5.size() << '\n'; // 2
my_vector<int> v6{from_arglist, 13, 13}; std::cout << v6.size() << '\n'; // 2
}
汎用コードでinitializer_list
を使用すると、括弧のタイプに応じて異なる動作をしてつながることができます選ばれたまた、このようなコンストラクタを追加することで、コードを静かに変更することも可能です。
もう一つの理由は、移動のみのタイプです:可変長引数テンプレートに
//std::vector<move_only> m1{move_only{}}; // won't compile
my_vector<move_only> m2{from_arglist, move_only{}}; // works fine
'exp_sequence'トリックはきちんとしていますが、要素を正しい順序で挿入することは実際に保証されていますか? AFAIR、CおよびC++は、関数の引数を語彙順に評価することを決して約束しませんでした。したがって、可変的なテンプレートコンストラクタの引数評価順序についてC++ 11標準に特別な保証がない限り、これは移植性がありません。 – fgp
@fgp:引数評価の順序は、実際には左から右に順序付けられることが保証されています。これは、中括弧の初期化を使用するたびに保持されます(したがって、exp_sequenceはクラスでなければなりません)。 – ipc
@ipc 'exp_sequence {(data.push_back(std :: forward
、引数の数は、(sizeof...
経由でアクセス可能)コンパイル時に知られています。 std::initializer_list
では、引数の数は実行時にのみ認識されます。だから決定の一部はあなたが必要とするか、あなたが持っている引数の数を知りたい時に依存します。
コンテナは完全な状態で初期化する必要があるため、コンパイル時のサイズを持ちます(push_backなどはできません)。 ':: size()'メソッドが 'constexpr'とマークされていないということを意味するなら、これはC++ 11の不具合であり、C++ 14で修正されました。名前付き 'initializer_list'などのサイズをさまざまな形でテンプレート化することができます。サイズはコンパイル時に利用できます。しかし、確かに、多分variadicオプションと同じくらい多くの方法ではありません! –
'initializer_list'のコンストラクタ_parameter_は、コンパイル時に知られているサイズを持っていません。なぜなら、各サイトで異なるサイズのイニシャライザを持つ複数のサイトからコンストラクタを呼び出すことができるからです。 – KnowItAllWannabe
ええ、素晴らしい点、私は完全に前に考えていなかった:) –
- 1. のstd ::コンストラクタでinitializer_list変換
- 2. MQTTとXMPPのどちらを選択すればよいですか?
- 3. initializer_listの場合に転送コンストラクタをオーバーロードするのはなぜですか?
- 4. WPFとローカルデータベースのどちらを選択するのですか?
- 5. E_NOTIMPLとE_NOINTERFACEのどちらを選択するのですか?
- 6. :: std :: initializer_listとvariadicテンプレート
- 7. 違いSAXParserFactory XMLReaderFactory。どちらを選択するのですか?
- 8. コンパイラはvectorとinitializer_listのどちらを決定するのですか?
- 9. どのレイアウトを選択すればよいですか?
- 10. std :: vectorとstd :: unordered_mapの選択肢いくつかの項目を検索する場合?
- 11. どのNoSqlソリューションを選択すればよいですか?
- 12. MongoDBから選択した値を選択するにはどうすればよいですか?
- 13. std :: initializer_list <int>({1,2,3})と{1,2,3}の違いは何ですか?
- 14. const auto std :: initializer_list ClangとGCCの違い
- 15. initializer_listの要素を移動するにはどうすればよいですか?
- 16. 同じテーブルから選択して挿入しない場合はどうすればいいですか?
- 17. asp.net webformとmvcアプリケーションのどちらを選択しますか?
- 18. コンパイラのbrace-initializer-listが `std :: initializer_list`型とどの程度密接に結合されていますか?
- 19. のstd :: is_nothrow_constructibleコンストラクタが継承されている場合
- 20. MySQL Left Join、NULLの場合は、どちらか一方からフィールドを選択します。
- 21. Capybara/Poltergeistのドロップダウンメニューから項目を選択した場合はどうすればテストできますか?
- 22. Reactで 'export'と 'default export'のどちらを選択するのですか?
- 23. 私の場合に合併する場合、どのように選択するのですか?
- 24. 結合が複数の行に一致する場合、1つの表から行を選択するにはどうすればよいですか?
- 25. ボタングループを選択すると、他のものが選択されていない場合、どのようにボタングループを作ることができますか?Javascript
- 26. 選択したセルより下の範囲を選択するにはどうすればよいですか?
- 27. Betweeen SpringスケジューラとJMSのどちらを選択するのですか?そしてそれらの違い
- 28. どのブックマークアイテムを選択/選択解除するには、どのブックマークアイテムにアクセスすればよいですか?
- 29. constexpr initializer_listコンストラクタを使用するとMSVCがコンパイルされない
- 30. C++ 11:関数からstd :: initializer_listを返すことはできますか?
私はわかりません(なぜこれがコメントなのですか)が、バリデーションテンプレートはさまざまなタイプを処理できませんが、イニシャライザリストはすべて同じタイプでなければなりませんか? –
@JoachimPileborg、絶対に正しいですが、あなたは 'int ...'と 'std :: initializer_list'の間で選択できます。私は使用するのが自然であると感じる方を選んで言う。 –
chris