enable_if with copy constructors

use*_*586 6 c++ templates sfinae enable-if

我第一次尝试std :: enable_if并且正在努力.任何指导将不胜感激.

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

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

所以vector类是:

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

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

    const double* data() const
    {
        return _data;
    }
...
};
Run Code Online (Sandbox Code Playgroud)

复制构造函数应该支持这样的东西,将v3的前2个元素复制到v2中:

Vector<3> v3;
Vector<2> v2(v3);
Run Code Online (Sandbox Code Playgroud)

我尝试了一个行为的复制构造函数1.像这样编译:

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);
    }
Run Code Online (Sandbox Code Playgroud)

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

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);
    }
Run Code Online (Sandbox Code Playgroud)

我也尝试在参数中添加enable_if,但它无法推断出_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);
    }
Run Code Online (Sandbox Code Playgroud)

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

谢谢

ild*_*arn 7

忽略默认值,这两个构造函数的签名是

template <size_t N, typename>
Vector(const Vector<N>&)
Run Code Online (Sandbox Code Playgroud)

即,它们最终是一样的.

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

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);
    }
Run Code Online (Sandbox Code Playgroud)

顺便说一句,名称喜欢_Size_OtherSize保留用于实现,因此对用户代码是非法的 - 丢失下划线和/或大写字母.

另外,正如@StoryTeller暗示的那样,当_OtherSize == _Size编译器生成的复制构造函数具有理想的行为时,您不希望第一个构造函数应用.对于相同大小的Vectors,所述构造函数已经不如复制构造函数那么专业化,因此无论如何都不会在重载决策期间选择它,但最好通过切换<=到目的来明确意图<.

  • @StoryTeller:你的意思是构造函数不适用而不是编译器生成的copy-c'tor?是的,可能,但我试图限制代码语言问题的答案,而不是逻辑问题(OP没有询问).不过好点,我会记下一点 - 谢谢! (2认同)
  • 毕竟,在重载解析期间永远不会应用它.没有模棱两可的风险,除了OP想知道为什么他们的断点没有被击中:) (2认同)