这是一个非常简单的类,表示三行 double ,每行附加一些字符串信息:
struct ThreeRows {
std::vector<double> row1;
std::vector<double> row2;
std::vector<double> row3;
std::string row1info;
std::string row2info;
std::string row3info;
};
我想做的是通过以下方式概括这种类型:
行不应再固定为三行,但作为类型的一部分应支持任意数量的行。
我应该能够指定每一行中的类型。也许我想要第一行的
double
和第二行的int
。 (将此示例设为两行类。)最后,除了
string
之外,我应该能够将其他信息附加到行中。例如(继续第 2 点中的示例),我可能想将string
附加到第一行,但将自定义rss_feed
附加到第二行。
如果模板允许(它们不允许),我想输入类似这样的内容来获取我的类型:
Rows<{double,int}, {string,rss_feed}>
由此确定的行数,或者如果我真的必须:
Rows<{double,int}, {string,rss_feed}, 2>
但这是不可能的。
可以做些什么吗?如果可以,我将如何使用此类模板?我如何实际获取我的 vector 和信息对象并使用它们?
最佳答案
使用一些模板魔法,您的问题可以通过可变参数模板和模板递归来解决。
template< size_t N, typename T, typename U, typename... Ts >
struct Rows : public Rows<N-1, Ts...> {
vector<T> row;
U rowinfo;
};
template<typename T, typename U>
struct Rows<1, T, U> {
vector<T> row;
U rowinfo;
};
Rows< 3, int, string, float, string, double, rss_feed > rows;
=> struct Rows {
vector<int> v1;
string s1;
vector<foat> v2;
string s2;
vector<double> v3;
rss_feed feed;
}
要访问这些字段的值,您可以实现模板化 get()
成员函数
template< size_t N, typename T, typename U, typename... Ts >
struct Rows : public Rows<N-1, Ts...> {
vector<T> row;
U rowinfo;
template< size_t M >
typename enable_if< M == N, tuple<vector<T>&, U&> >::type
get() {
return make_tuple( ref(row), ref(rowinfo) );
}
};
template<typename T, typename U>
struct Rows<1, T, U> {
vector<T> row;
U rowinfo;
template< size_t M >
typename enable_if< M == 1, tuple<vector<T>&, U&> >::type
get() {
return make_tuple( ref(row), ref(rowinfo) );
}
};
花点时间消化这些。 get()
方法返回一个元组,其中包含对请求字段的引用,并且仅当传入的数字与类的模板匹配时才启用它们,其他数字呢?好吧,我们可以像这样启用它们
template< size_t M >
typename enable_if< M != N, tuple<vector<T>&, U&> >::type
get() {
return Rows<N-1, Ts...>::template get<M>(); // call parent's get,
// ::template is required to avoid ambiguity
}
但这是错误的!!!返回类型不是 tuple<vector<T>&, U&>
,应该是tuple<vector<A>&, B&>
其中 A
和 B
是可变参数模板中的相应类型 Ts...
但是我们到底是怎么从 Ts...
得到我们想要的类型的呢? ,那么我们可以使用以下技术找出可变参数模板的类型。
template< size_t N, typename... Ts >
struct variadic_type;
template< typename T, typename U, typename... Ts >
struct variadic_type< 0, T, U, Ts... > {
typedef T T_type;
typedef U U_type;
};
template< size_t k, typename T, typename U, typename... Ts >
struct variadic_type< k, T, U, Ts... > {
typedef typename variadic_type< k-1, Ts... >::T_type T_type;
typedef typename variadic_type< k-1, Ts... >::U_type U_type;
};
所以 variadic_type< 1, int, int, short, short, float, float >::T_type
和 U_type
将是 short
和 short
.
现在我们有办法找出可变参数模板上特定位置的类型,我们可以将它应用于我们的错误 get()
获取正确返回类型的方法...
template< size_t M >
typename
enable_if< M != N,
tuple<
vector<typename variadic_type< N-M, T, U, Ts...>::T_type>&,
typename variadic_type< N-M, T, U, Ts...>::U_type&
> >::type
get() {
return Rows<N-1, Ts...>::template get<M>();
}
我们完成了,我们可以调用get()
喜欢
Rows< 3, int, string, double, string, float, string > rows;
auto r3 = rows.get<3>(); // { vector<int>& v, string& s };
auto r2 = rows.get<2>(); // { vector<double>& v, string& s };
auto r1 = rows.get<1>(); // { vector<float>& v, string& s };
auto r4 = rows.get<4>(); // error:: other numbers will not compile!!
现在处理索引规则不是很愉快,但我认为这可以理解这个想法。
关于c++ - 这可以用 C++ 中的模板来完成吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16349780/