c++ - 这可以用 C++ 中的模板来完成吗?

标签 c++

这是一个非常简单的类,表示三行 double ,每行附加一些字符串信息:

struct ThreeRows {
  std::vector<double> row1;
  std::vector<double> row2;
  std::vector<double> row3;

  std::string row1info;
  std::string row2info;
  std::string row3info;
};

我想做的是通过以下方式概括这种类型:

  1. 行不应再固定为三行,但作为类型的一部分应支持任意数量的行。

  2. 我应该能够指定每一行中的类型。也许我想要第一行的 double 和第二行的 int 。 (将此示例设为两行类。)

  3. 最后,除了 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&>其中 AB是可变参数模板中的相应类型 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_typeU_type将是 shortshort .

现在我们有办法找出可变参数模板上特定位置的类型,我们可以将它应用于我们的错误 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/

相关文章:

c++ - 如何在 Win32 应用程序中控制焦点?

c++ - 使用 Bootstrap/BoostBuild 和 Visual Studio 2015 安装 boost

c++ - 使用 vector 和 QVector 进行奇怪的内存管理

C++ 比较 vector

c++ - 按值捕获的广义 lambda 始终位于同一地址

c++ - 如何在 C++ 中创建并行事件(特定于 Qt 4.6)

C 主项目中的 C++ 静态库

c++ - 恐惧的怪异行为

C++:模板问题 (C2064)

c++ - QT串口不工作