具有初始化列表的结构模板和构造函数
Struct template and constructor with initializer list
我试图更好地理解模板,为此我制作了一个教育结构:
template<typename T, size_t N>
struct SVectorN
{
SVectorN(const T(&another)[N]);
private:
T components[N];
};
我创建的构造函数允许我创建一个实例,如下所示:
double input[4] = { 0.1, 0.2, 0.3, 0.4 };
SVectorN<double, 4> t(input);
但我不知道如何支持这样的初始化:
SVectorN<double, 4> c = { 1.3, 1.4, 1.5, 1.6 };
或者像这样更好:
SVectorN c(1.3, 1.4, 1.5, 1.6 ); // SVectorN<double, 4>
有可能还是我完全遗漏了什么?
谢谢
这两种方法都是可行的,C++ 中的初始化很棘手,原因很简单,因为有很多方法,而且它们之间存在细微差别。
我会推荐这样的东西:
#include <cstdint>
#include <utility>
template <typename T, std::size_t N> struct SVectorN {
SVectorN(const T (&another)[N]);
template <typename First, typename Second, typename... Tail>
SVectorN(First &&f, Second &&s, Tail &&...t)
: components{std::forward<First>(f), std::forward<Second>(s),
std::forward<Tail>(t)...} {}
private:
T components[N];
};
int main() {
double input[4] = {0.1, 0.2, 0.3, 0.4};
SVectorN<double, 4> t(input);
SVectorN<double, 4> c = {1.3, 1.4, 1.5, 1.6};
SVectorN<double, 4> d{1.3, 1.4, 1.5, 1.6};
SVectorN<double, 4> e(1.3, 1.4, 1.5, 1.6);
}
我必须明确强制在可变参数 ctor 中存在至少两个参数,否则它会更好地匹配 t
的构造并且会失败。
如果 std::initializer_list
没有 ctor,c,d,e
实际上是相同的初始化。没有,因为用一个初始化数组不容易完成。
现在,如果您想自动推导模板参数,这要归功于 CTAD。为了简化 link,您只需向编译器指定如何从构造函数的参数中推断出 class 的模板参数。
例如:
template <class T, std::size_t N>
explicit SVectorN(const T (&)[N]) -> SVectorN<T, N>;
template <typename F, typename S, typename... Tail>
SVectorN(F &&, S &&, Tail &&...) -> SVectorN<F, sizeof...(Tail) + 2>;
将允许:
SVectorN tx(input);
SVectorN cx = {1.3, 1.4, 1.5, 1.6};
SVectorN dx{1.3, 1.4, 1.5, 1.6};
SVectorN ex(1.3, 1.4, 1.5, 1.6);
我真的很喜欢@Quimby 的回答,但我不确定它是否适用于一个论点。或者,您可以使用 std::initializer_list
和 variadic
重载构造函数。现阶段效率不是很高,但您可以根据需要进行优化。
#include <iostream>
template <typename T, size_t N>
struct SVectorN
{
private:
T components[N];
public:
SVectorN(const T(&another)[N])
{
std::copy(std::begin(another), std::end(another), components);
}
SVectorN(std::initializer_list<T> &&init_)
{
std::copy(std::begin(init_), std::end(init_), components);
}
template <typename ... U>
SVectorN(U ...val_)
{
T tmp[] = { val_ ... };
std::copy(std::begin(tmp), std::end(tmp), components);
}
void print() const
{
for (auto &&c : components)
std::cout<< c <<",";
std::cout<<std::endl;
}
};
int main()
{
double input[4] = { 0.1, 0.2, 0.3, 0.4 };
SVectorN<double, 4> t(input);
t.print();
SVectorN<double, 4> c = { 1.3, 1.4, 1.5, 1.6 };
c.print();
SVectorN<double, 4> d(1.3, 1.4, 1.5, 1.6 );
d.print();
}
结果是:
0.1,0.2,0.3,0.4,
1.3,1.4,1.5,1.6,
1.3,1.4,1.5,1.6,
我试图更好地理解模板,为此我制作了一个教育结构:
template<typename T, size_t N>
struct SVectorN
{
SVectorN(const T(&another)[N]);
private:
T components[N];
};
我创建的构造函数允许我创建一个实例,如下所示:
double input[4] = { 0.1, 0.2, 0.3, 0.4 };
SVectorN<double, 4> t(input);
但我不知道如何支持这样的初始化:
SVectorN<double, 4> c = { 1.3, 1.4, 1.5, 1.6 };
或者像这样更好:
SVectorN c(1.3, 1.4, 1.5, 1.6 ); // SVectorN<double, 4>
有可能还是我完全遗漏了什么?
谢谢
这两种方法都是可行的,C++ 中的初始化很棘手,原因很简单,因为有很多方法,而且它们之间存在细微差别。
我会推荐这样的东西:
#include <cstdint>
#include <utility>
template <typename T, std::size_t N> struct SVectorN {
SVectorN(const T (&another)[N]);
template <typename First, typename Second, typename... Tail>
SVectorN(First &&f, Second &&s, Tail &&...t)
: components{std::forward<First>(f), std::forward<Second>(s),
std::forward<Tail>(t)...} {}
private:
T components[N];
};
int main() {
double input[4] = {0.1, 0.2, 0.3, 0.4};
SVectorN<double, 4> t(input);
SVectorN<double, 4> c = {1.3, 1.4, 1.5, 1.6};
SVectorN<double, 4> d{1.3, 1.4, 1.5, 1.6};
SVectorN<double, 4> e(1.3, 1.4, 1.5, 1.6);
}
我必须明确强制在可变参数 ctor 中存在至少两个参数,否则它会更好地匹配 t
的构造并且会失败。
std::initializer_list
没有 ctor,c,d,e
实际上是相同的初始化。没有,因为用一个初始化数组不容易完成。
现在,如果您想自动推导模板参数,这要归功于 CTAD。为了简化 link,您只需向编译器指定如何从构造函数的参数中推断出 class 的模板参数。
例如:
template <class T, std::size_t N>
explicit SVectorN(const T (&)[N]) -> SVectorN<T, N>;
template <typename F, typename S, typename... Tail>
SVectorN(F &&, S &&, Tail &&...) -> SVectorN<F, sizeof...(Tail) + 2>;
将允许:
SVectorN tx(input);
SVectorN cx = {1.3, 1.4, 1.5, 1.6};
SVectorN dx{1.3, 1.4, 1.5, 1.6};
SVectorN ex(1.3, 1.4, 1.5, 1.6);
我真的很喜欢@Quimby 的回答,但我不确定它是否适用于一个论点。或者,您可以使用 std::initializer_list
和 variadic
重载构造函数。现阶段效率不是很高,但您可以根据需要进行优化。
#include <iostream>
template <typename T, size_t N>
struct SVectorN
{
private:
T components[N];
public:
SVectorN(const T(&another)[N])
{
std::copy(std::begin(another), std::end(another), components);
}
SVectorN(std::initializer_list<T> &&init_)
{
std::copy(std::begin(init_), std::end(init_), components);
}
template <typename ... U>
SVectorN(U ...val_)
{
T tmp[] = { val_ ... };
std::copy(std::begin(tmp), std::end(tmp), components);
}
void print() const
{
for (auto &&c : components)
std::cout<< c <<",";
std::cout<<std::endl;
}
};
int main()
{
double input[4] = { 0.1, 0.2, 0.3, 0.4 };
SVectorN<double, 4> t(input);
t.print();
SVectorN<double, 4> c = { 1.3, 1.4, 1.5, 1.6 };
c.print();
SVectorN<double, 4> d(1.3, 1.4, 1.5, 1.6 );
d.print();
}
结果是:
0.1,0.2,0.3,0.4,
1.3,1.4,1.5,1.6,
1.3,1.4,1.5,1.6,