是否可以使用C++11 initializer_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}。如果initializer_list
中有一个constexpr tail
函数,我认为它应该可以工作。
是的,以一种迂回的方式,有效地将初始值设定项列表拆包并重新打包为更合适的格式。然而,还有一种更好的(imho)方法:变分模板。
#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
作为基本情况,因为它更有意义。
我没有编译器可以编译它,但我认为正确的答案是:
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;
};
对于递归结构,初始值设定项列表必须递归地传递给采用迭代器的构造函数。
解决方案是创建一个名为的函数
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一起工作,而不与其他任何东西一起测试。就规则而言,这可能是不正确的。