首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >可变模板模板

可变模板模板
EN

Stack Overflow用户
提问于 2011-04-15 09:21:02
回答 2查看 692关注 0票数 2

我正在尝试创建一个基类,它是std::array的包装器,它重载了一堆常见的算术运算符。最终结果将类似于std::valarray,但具有静态大小。我这样做是因为我正在为我的库创建一整套子类,这些子类最终复制了这个功能。例如,我需要创建一个MyPixel类和一个MyPoint类,这两个类本质上都是静态大小的数组,我可以对其执行算术运算。

我的解决方案是创建一个StaticValArray基类,MyPoint和MyPixel可以从中派生。但是,为了禁止用户向MyPixel添加MyPoint,我使用的是CRTP模式:

代码语言:javascript
运行
复制
template<class T1, class T2>
struct promote
{
  typedef T1 type; // Assume there is a useful type promotion mechanism here
};

template<class T, size_t S, template<typename... A> class ChildClass>
class StaticValArray : public std::array<T,S>
{
  public:
    // Assume there are some conversion, etc. constructors here...

    template<class U>
    StaticValArray<typename promote<T,U>::type,S,ChildClass> operator+ 
        (StaticValArray<U,S,ChildClass> const & rhs)
    {
      StaticValArray<typename promote<T,U>::type,S,ChildClass> ret = *this;
      std::transform(this->begin(), this->end(),
          rhs.begin(), ret.begin(), std::plus<typename promote<T,U>::type>());
      return ret;
    }


    // More operators....
};

这非常酷,因为ChildClass可以有任意的类模板参数,并且这个东西可以工作。例如:

代码语言:javascript
运行
复制
template<class T, class U>
class MyClassTwoTypes : public StaticValArray<T,3,MyClassTwoTypes>
{ };

template<class T, class U>
class MyClassTwoTypes2 : public StaticValArray<T,3,MyClassTwoTypes2>
{ };

int main()
{
  MyClassTwoTypes<int, float> p;
  MyClassTwoTypes<double, char> q;
  auto z = p + q;

  MyClassTwoTypes2<double, char> r;
  //  r += q;  // <-- Great! This correctly won't compile

  return 0;
}

我的问题是:我想在StaticValArray的CRTP位中填充一些ChildClass,它不一定只将类作为其模板参数。例如,考虑以下N维Point类:

代码语言:javascript
运行
复制
template<class T, size_t S>
class MyPointND : public StaticValArray<T,S,MyPointND>
{ };

不幸的是,这不能编译,因为size_t不是一个类型名--我得到了编译器错误:

代码语言:javascript
运行
复制
type/value mismatch at argument 3 in template parameter list for ‘template<class T, long unsigned int S, template<class ... A> class ChildClass> class StaticValArray’
test.C:36:54: error:   expected a template of type ‘template<class ... A> class ChildClass’, got ‘template<class T, long unsigned int S> class MyPointND’

有没有办法创建一个可变模板参数包,它完全可以是任何东西(类型名、整型数、size_t、双精度数等等?)因为最后我真的不关心里面的类型是什么。请注意,我不能完全指定ChildClass (例如class MyPointND: public StaticValArray<T,S,MyPointND<T,S>>),因为这会破坏我的类型提升机制。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-04-15 16:59:36

如果您使用std::integral_constant代替size_t,会怎么样呢?您可以将数组大小的数值嵌入其中,并且可以将其用作类型。

编辑

为了减少冗长,您可以定义自己的整型常量类,如下所示:

代码语言:javascript
运行
复制
template <std::size_t N>
struct size_ : std::integral_constant<std::size_t,N> {};

然后你可以像这样使用它:

代码语言:javascript
运行
复制
MyPointND<int,size_<3>> x;
票数 3
EN

Stack Overflow用户

发布于 2011-04-15 20:21:51

您需要做的是创建一个traits类,专门用于每种类型,其中包含类型提升所需的所有内容,然后将完整的类型传递给StaticValArray。

此外,使用decltype,你不应该需要这样的东西- decltype会告诉你通过添加一个浮点型和一个整型得到的结果。

代码语言:javascript
运行
复制
template<class U>
StaticValArray<decltype(*(T*)nullptr + *(U*)nullptr),S,ChildClass> operator+ 
    (StaticValArray<U,S,ChildClass> const & rhs)
{
  StaticValArray<decltype(*(T*)nullptr + *(U*)nullptr),S,ChildClass> ret = *this;
  std::transform(this->begin(), this->end(),
      rhs.begin(), ret.begin(), std::plus<decltype(*(T*)nullptr + *(U*)nullptr)>());
  return ret;
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5671479

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档