具有复制构造函数的enable_if [英] enable_if with copy constructors

查看:69
本文介绍了具有复制构造函数的enable_if的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在第一次尝试 std :: enable_if ,并且很挣扎.任何指导将不胜感激.

作为一个玩具示例,这是一个简单的静态 vector 类,我想为其定义一个副本构造函数,但其​​行为取决于矢量的相对大小:

  1. 只需将数据复制到较小或相同大小的向量中
  2. 将数据复制到更大的向量中,然后用零填充其余部分

所以 vector 类是:

 模板< size_t _Size>类向量{双重_data [_Size];上市:向量(){std :: fill(_data,_data + _Size,0.0);}const double * data()const{返回_data;}//...}; 

复制构造函数应支持以下内容:将 v3 的前两个元素复制到 v2 :

  Vector< 3>v3;向量2.v2(v3); 

我尝试了行为1的副本构造函数,如下所示,它可以编译:

 模板< size_t _OtherSize,typename = typename std :: enable_if_t< _Size< = _OtherSize>>Vector(const Vector< _OtherSize>& v):Vector(){std :: copy(v.data(),v.data()+ _Size,_data);} 

,但是即使 enable_if 条件是互斥的,编译器也无法将其与行为2区分开.

 模板< size_t _OtherSize,typename = typename std :: enable_if_t< _OtherSize<_Size>>Vector(const Vector< _OtherSize>& v):Vector(){std :: copy(v.data(),v.data()+ _OtherSize,_data);std :: fill(_data + _OtherSize,_data + _Size,0.0);} 

我还尝试将 enable_if 放到参数中,但是它不能推断出 _OtherSize 的值:

 模板< size_t _OtherSize>向量(const typename std :: enable_if_t< _Size< = _OtherSize,向量< _OtherSize>>&v):Vector(){std :: copy(v.data(),v.data()+ _Size,_data);} 

执行此操作的方式是什么(使用 enable_if ,而不是简单的 if 语句)?

解决方案

忽略默认值,这些构造函数的 both 的签名为

 模板< size_t N,类型名>向量(const Vector< N&) 

也就是说,它们最终是相同的.

区分它们的一种方法是使模板参数类型直接取决于 enable_if 的条件:

 模板< size_t _OtherSize,std :: enable_if_t<(_ Size< = _OtherSize),int>= 0>Vector(const Vector< _OtherSize>& v):Vector(){std :: copy(v.data(),v.data()+ _Size,_data);}模板< size_t _OtherSize,std :: enable_if_t<(_ OtherSize< _Size),int>= 0>Vector(const Vector< _OtherSize>& v):Vector(){std :: copy(v.data(),v.data()+ _OtherSize,_data);std :: fill(_data + _OtherSize,_data + _Size,0.0);} 


顺便说一句,像 _Size _OtherSize 之类的名称保留用于实现,因此对于用户代码而言是非法的–丢失了下划线和/或大写字母.

此外,正如@StoryTeller所暗示的那样,您也不希望在 _OtherSize == _Size 时应用第一个构造函数,因为编译器生成的副本构造函数具有理想的行为.对于相同大小的 Vector 来说,该构造函数已经不如复制构造函数专门,因此无论如何在重载解析期间都不会选择它,但是最好通过切换< = 到< .

I am trying std::enable_if for the first time and struggling. Any guidance would be appreciated.

As a toy example, here is a simple static vector class, for which I want to define a copy constructor, but the behavior depends on the relative sizes of the vectors:

  1. just copy data into a smaller or same-sized vector
  2. copy data into a larger vector and then pad the rest with zeroes

So the vector class is:

template <size_t _Size>
class Vector
{
    double _data[_Size];

public:
    Vector()
    {
        std::fill(_data, _data + _Size, 0.0);
    }

    const double* data() const
    {
        return _data;
    }

    // ...
};

The copy constructor should support something like this: copying the first 2 elements of v3 into v2:

Vector<3> v3;
Vector<2> v2(v3);

I tried a copy constructor for behavior 1. like this, which compiles:

template <size_t _OtherSize,
typename = typename std::enable_if_t<_Size <= _OtherSize>>
Vector(const Vector<_OtherSize>& v) : Vector()
{
   std::copy(v.data(), v.data() + _Size, _data);
}

but the compiler cannot distinguish this from behavior 2. even though the enable_if conditions are mutually exclusive.

template <size_t _OtherSize,
typename = typename std::enable_if_t<_OtherSize < _Size>>
Vector(const Vector<_OtherSize>& v) : Vector()
{
    std::copy(v.data(), v.data() + _OtherSize, _data);
    std::fill(_data + _OtherSize, _data + _Size, 0.0);
}

I also tried putting enable_if in the argument instead, but it couldn't deduce the value of _OtherSize:

template <size_t _OtherSize>
    Vector(const typename std::enable_if_t<_Size <= _OtherSize, 
    Vector<_OtherSize>> & v)
    : Vector()
    {
        std::copy(v.data(), v.data() + _Size, _data);
    }

What is the way to do this (using enable_if, not a simple if statement)?

解决方案

Ignoring defaults, the signature of both of those constructors is

template <size_t N, typename>
Vector(const Vector<N>&)

I.e., they're ultimately the same.

One way to differentiate them is to make the template parameter type directly dependent on enable_if's condition:

template <size_t _OtherSize,
    std::enable_if_t<(_Size <= _OtherSize), int> = 0>
    Vector(const Vector<_OtherSize>& v) : Vector()
    {
        std::copy(v.data(), v.data() + _Size, _data);
    }

template <size_t _OtherSize,
    std::enable_if_t<(_OtherSize < _Size), int> = 0>
    Vector(const Vector<_OtherSize>& v) : Vector()
    {
        std::copy(v.data(), v.data() + _OtherSize, _data);
        std::fill(_data + _OtherSize, _data + _Size, 0.0);
    }


As an aside, names like _Size and _OtherSize are reserved for the implementation and thus illegal for user code – lose the underscore and/or the capital letter.

Also, as @StoryTeller hinted at, you don't want the first constructor to apply when _OtherSize == _Size, as the compiler-generated copy constructor has ideal behavior. Said constructor is already less specialized than the copy constructor for same-sized Vectors, so it won't be selected during overload resolution anyway, but it would be best to make the intent clear by switching <= to <.

这篇关于具有复制构造函数的enable_if的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆