3

サイズに合わせてテンプレート化された配列を使用する小さなクラスを作成しています。ここにいくつかのコードがあります...

.hpp

template <size_t N>
class KeyCombinationListener
{
public:
    KeyCombinationListener(
        const std::array<sf::Keyboard::Key, N>& sequence,
        std::function<void (void)> fn
        );

private:
    std::array<sf::Keyboard::Key, N>  combo;
    std::function<void (void)>  callback;
};

.cc

template <size_t N>
KeyCombinationListener<N>::KeyCombinationListener(
    const array<sf::Keyboard::Key, N>& sequence, function<void (void)> fn
    ) : combo(sequence), progress{begin(combo)}, callback{fn}
{

}

combo{sequence}コンストラクタのメンバ初期化では、型しか受け付けないのでイニシャライザとして使えませんsf::Keyboard::Key。を要求している場合、これは理にかなっていますinitializer_listが、これは奇妙に思えます。他の標準コンテナーでは、{} 表記を使用してコピー コンストラクターを呼び出すことができます。これはとの癖std::arrayですか?それとも私のclangのバグですか?

念のため、私のclangバージョンは次のとおりです。

Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)
Target: x86_64-pc-linux-gnu
Thread model: posix
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9.2
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.9
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.9.2
Selected GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9
Candidate multilib: .;@m64
Selected multilib: .;@m64
4

1 に答える 1

3

C++ で欠陥が発生しました: 単一要素からのリストの初期化。C++11 および C++14 国際標準で規定されている動作は驚くべきものです。以下では C++14 について説明します。

テンプレートのインスタンス化std::arrayは集約[array.overview]/2です。したがって、 braced -init-liststd::arrayからオブジェクトを初期化する場合、初期化子[dcl.init.list]/3.1の数を無差別に集約初期化が実行されます。他のコンテナ クラスは、特定の構造 (イテレータのペアなど) の要件のため、集約にすることはできません。

集約初期化は、初期化子からのデータ メンバーを (場合によっては再帰的に) 初期化します。あなたの場合、イニシャライザstd::array<sf::Keyboard::Key, N>からの最初のデータメンバーを初期化しようとしますsequence(これは同じタイプです)。std::array私が知っているのすべての実装では、 の最初のデータ メンバーstd::arrayは C スタイルの配列です。リスト初期化は、元の初期化子からその配列の最初の要素を初期化しようとします: sequence.

例:

struct aggregate
{
    int m[2];
};

aggregate x = {0, 1};
assert(x.m[0] == 0 && x.m[1] == 1);

aggregate y{x}; // error: cannot convert `aggregate` to `int`

最後の行の初期化は、から初期化しようとしy.m[0]ますx


CWG issue 1467では、これと関連する問題 (初期化子がない場合のリストの初期化) について説明しています。提案された解決策では、OPの問題をカバーするリスト初期化の(さらに別の)特別なケースが導入されています。最近の github ドラフト [dcl.init.list]/3.1 を引用

Tがクラス型であり、イニシャライザ リストに型cv の要素が 1 つある場合U(ここで、UTまたは から派生したクラスT)、オブジェクトはその要素から初期化されます (コピー リスト初期化の場合はコピー初期化、または直接初期化による場合)。直接リスト初期化)。

最近のドラフトの集約初期化は、「優先度」が低く (3.3)、つまり、上記の条件が満たされない場合にのみ実行されます。


g++ (5.0) および clang++ (3.7.0) の最近のバージョンでは、C++11 モードでも提案された解決策が実装されています。

于 2015-04-03T23:23:55.503 に答える