如何复用类模板参数中的变参模板,使Data类型匹配Bar的原始参数包?
如何从继承的Bar类中获取原始参数包初始化Data类型?
现有如下C++代码,其中Container<BarImpl>的data成员当前类型为Data<std::tuple<Foo<int, int>, Foo<int, float>, Foo<float, float>>>,但我们需要它直接是Data<Foo<int, int>, Foo<int, float>, Foo<float, float>>——也就是拿到Bar的原始模板参数包,而非打包后的tuple类型:
template <typename K, typename V> class Foo{ typedef K valueTypeK; typedef V valueTypeV; }; template<class... Foo> class Bar{ public: // capture Foo... parameter package using FooTuple = std::tuple<Foo...>; }; template <class... Foo> class Data{ // capture Foo... parameter package using FooTuple = std::tuple<Foo...>; }; // assuming T inherits from Bar template<class T> class Container{ // I'd like Data to be of type "Data<Foo...> " // but it will be of type "Data<std::tuple<Foo...>>" Data<typename T::FooTuple> data; }; class BarImpl : public Bar<Foo<int, int>, Foo<int, float>, Foo<float, float>> {}; int main(){ BarImpl bar_impl; Container<BarImpl> container_impl; }
解决方案一:在Bar中直接暴露参数包的应用接口
修改Bar类,新增一个模板别名,直接将原始参数包传递给目标模板类型:
template<class... Foos> class Bar{ public: using FooTuple = std::tuple<Foos...>; // 新增:把原始参数包直接应用到任意模板类上 template<template<class...> class Target> using ApplyParamsTo = Target<Foos...>; };
然后修改Container类,直接使用这个别名生成目标Data类型:
template<class T> class Container{ // 直接获取展开参数包后的Data类型 typename T::template ApplyParamsTo<Data> data; };
解决方案二:通过类型萃取从tuple中提取参数包
如果无法修改Bar类,可以编写一个类型萃取工具,从std::tuple中解析出原始模板参数:
// 基础萃取模板 template<class Tuple> struct TupleParamExtractor; // 针对std::tuple的特化实现 template<class... Args> struct TupleParamExtractor<std::tuple<Args...>>{ template<template<class...> class Target> using Apply = Target<Args...>; };
接着修改Container类,利用萃取工具生成目标类型:
template<class T> class Container{ // 从tuple中提取参数包,再传递给Data typename TupleParamExtractor<typename T::FooTuple>::template Apply<Data> data; };
两种方法都能实现需求:方案一更简洁直接,无需额外工具类;方案二无需改动原有Bar代码,适合无法修改基础类的场景。
内容的提问来源于stack exchange,提问作者user3641187
相关产品推荐
相关产品推荐

