2

是否可以使用 C++11initializer_list来组装递归定义的类,例如Foo,使用constexpr构造函数:

template <size_t N>
struct Foo {
  constexpr Foo(int x, Foo<N-1> f) : x(x), xs(xs) {}
  int x;
  Foo<N-1> xs;
};

template <> struct Foo<0> {};

我可以初始化一个Foo<3>使用:

int main(int argc, char *argv[])
{
  Foo<3> a = Foo<3>(1,Foo<2>(2,Foo<1>(3,Foo<0>())));
  return 0;
}

最好使用 Foo<3> a = {1,2,3} 代替。如果有一个constexpr tail功能,initializer_list我认为它应该可以工作。

4

3 回答 3

9

是的,以一种迂回的方式,有效地将初始化列表解包和重新打包为更合适的格式。但是,有一种更好的(恕我直言)方式:可变参数模板。

#include <stddef.h>
#include <iostream>

template <size_t N>
struct Foo {
  template<class... Tail>
  constexpr Foo(int i, Tail... t) : x(i), xs(t...) {}

  void print(){
    std::cout << "(" << x << ", ";
    xs.print();
    std::cout << ")";
  }

  int x;
  Foo<N-1> xs;
};

template <> 
struct Foo<1> {
  constexpr Foo(int i) : x(i) {}
  void print(){ std::cout << "(" << x << ")"; }
  int x;
};

int main(){
 Foo<3> x = {1, 2, 3};
 x.print();
 std::cout << "\n";
}

按预期输出:

(1, (2, (3)))

请注意,我选择1了基本情况,因为它更有意义。

于 2012-03-13T00:09:53.803 回答
1

我没有可以编译它的编译器,但我认为正确的答案是:

template <size_t N>
struct Foo {
  constexpr Foo(int x, Foo<N-1> f)   //template iterator constructor
  : x(x), xs(xs) {}
  Foo(std::initializer_list<int> f)  //initializer list constructor
  : x(*f.begin()), xs(++f.begin(), f.end()) 
  { static_assert(xs.size()==N, "incorrect number of values in initializer list");}
  template<class iter>
  Foo(iter first, iter last)  //template iterator constructor
  : x(*first), xs(++first, last) {}  //UB if wrong number of values given

  int x;
  Foo<N-1> xs;
};

template <> 
struct Foo<1> { //I use 1 for smaller structures
  constexpr Foo(int f) 
  : x(f) {}
  Foo(std::initializer_list<int> f) 
  : x(*f.begin())
  { static_assert(xs.size()==1, "incorrect number of values in initializer list");}
  template<class iter>
  Foo(iter first, iter last)
  : x(*first)
  { assert(first+1 == last); } 

  int x;
};

对于递归结构,初始化器列表必须以递归方式传递给采用迭代器的构造函数。

于 2012-03-13T00:17:42.390 回答
0

解决方案是制作一个名为

template<class T>
constexpr T initlist_val(initializer_list<T>& list, int index) {
  return (index < list.size()) ? *(list.begin() + index) : 0;
}

现在你可以走了

class MyClass {
public:
  int A, int B;
  constexpr MyClass(const initializer_list<int>& list) : A(initlist_val(list,0)), B(initlist_val(1)) {
  // Put nothing here etc..
  }

};

你不需要所有其他的东西。这可以与未经其他任何测试的 GCC 一起使用。在规则方面可能是不正确的。

于 2014-07-01T03:41:00.290 回答