-1

例を挙げて尋ねるのが最も簡単な方法だと思います。次のタイプがあるとします。

class Node
{
  // make noncopyable
  Node(const Node& ref) = delete;      
  Node& operator=(const Node& ref) = delete;

  // but moveable
  Node(Node&& ref) = default;
  Node& operator=(Node&& ref) = default;

  // we do not have a default construction
  Node() = delete;
  Node(unsigned i): _i(i) {}

  unsigned _i;
};

今、これらのノードのいくつかを std::array に保存したいと思います:

template<unsigned count>
class ParentNode
{
  std::array<Node,count> _children;
  ParentNode() 
     // i cannt do this, since i do not know how many nodes i need
     // : _children{{Node(1),Node(2),Node(3)}}  
     : _children()  // how do i do this?
  {}
};

コメントで述べたように、質問は次のとおりです。これを行うにはどうすればよいですか? 子に渡される unsigned は、子が格納されている配列のインデックスでなければなりません。しかし、より一般的なソリューションも非常に高く評価されています!

私が見つけた次の解決策は、より複雑な型の未定義の動作になる可能性があります。明確に定義された適切な解決策については、受け入れられた回答を参照してください。

template<unsigned count>
class ParentNode
{
public:
   // return by value as this will implicitly invoke the move operator/constructor
   std::array<Node,count> generateChildren(std::array<Node,count>& childs)
   {
      for (unsigned u = 0; u < count; u++)
         childs[u] = Node(u);  // use move semantics, (correct?)

      return std::move(childs); // not needed
      return childs;  // return by value is same as return std::move(childs)
   }

  std::array<Node,count> _children;

  ParentNode() 
     // i cannt do this, since i do not know how many nodes i need
     // : _children{{Node(1),Node(2),Node(3)}}  
     : _children(generateChildren(_children))  // works because of move semantics (?)
  {}
};

ParentNode<5> f; 

コードはコンパイルされます。しかし、それが私が期待することをするかどうかはわかりません。たぶん、移動セマンティクスと右辺値参照に詳しい人がコメントを追加できます:-)

4

2 に答える 2

1

arrayバリアディックを使用して、インデックスの任意の関数に初期化された要素を持つを生成できます。インデックス シーケンスを生成するための標準的な機構の使用:

template <int... I> struct indices {};
template <int N, int... I> struct make_indices :
  make_indices<N-1,N-1,I...> {};
template <int... I> struct make_indices<0,I...> : indices<I...> {};

それはかなり簡単です:

template <typename T, typename F, int... I>
inline std::array<T, sizeof...(I)> array_maker(F&& f, indices<I...>) {
  return std::array<T, sizeof...(I)>{ std::forward<F>(f)(I)... };
}

template <typename T, std::size_t N, typename F>
inline std::array<T, N> array_maker(F&& f) {
  return array_maker<T>(std::forward<F>(f), make_indices<N>());
}

これにより、 の効果を複製することから何でもできますstd::iota:

auto a = array_maker<int,10>([](int i){return i;});

最初の 10 個の自然数の二乗を逆順に並べた配列を作成するには:

const auto a = array_maker<std::string,10>([](int i){
  return std::to_string((10 - i) * (10 - i));
});

あなたは可動であるため、コンストラクターをNode次のように定義できます。ParentNode

ParentNode() 
   : _children(array_maker<Node, count>([](unsigned i){return i+1;}))
{}

Coliru ですべてがまとめられたライブをご覧ください

于 2013-08-10T15:29:18.920 に答える
-1

本当に、できることはあまりありません。テンプレート パラメーターによって決定されるサイズの配列に既定のコンストラクターを持たない型を配置し、任意の値で要素を初期化する必要があるため、自分自身を窮地に追い込みました。

波括弧初期化リストに入れることができ、複数の要素を持つ配列 (または任意の種類の集合体) を初期化するために使用できる関数から返すことができるものは何もありません。{}「」という意味ではありませんinitializer_list。これは波括弧初期化リストであり、特定の状況下で になる可能性がありますが、コンストラクター呼び出しのパラメーターまたは集約の初期化で使用する要素になることもありますinitializer_list

あなたの最善の策は、実際には a を使用vectorして、ループで手動で初期化することです。

于 2013-08-10T12:29:33.497 に答える