我第一次尝试std :: enable_if并且正在努力。 任何指导都将不胜感激。
作为一个玩具示例,这里是一个简单的静态向量类,我想为其定义一个复制构造函数,但行为取决于向量的相对大小:
所以矢量类是:
template <size_t _Size>
class Vector
{
double _data[_Size];
public:
Vector()
{
std::fill(_data, _data + _Size, 0.0);
}
const double* data() const
{
return _data;
}
...
};
复制构造函数应该支持这样的东西,将v3的前2个元素复制到v2:
Vector<3> v3;
Vector<2> v2(v3);
我为行为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);
}
但是编译器无法将其与行为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);
}
我也尝试在参数中添加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);
}
执行此操作的最佳方法是什么(使用enable_if,而不是简单的if语句)?
由于
答案 0 :(得分:7)
忽略默认值,这些构造函数的两者的签名是
template <size_t N, typename>
Vector(const Vector<N>&)
即,它们最终是一样的。
区分它们的一种方法是使模板参数类型直接依赖于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);
}
顺便说一句,像_Size
和_OtherSize
这样的名称是为实现保留的,因此对于用户代码是非法的 - 丢失下划线和/或大写字母。
另外,正如@StoryTeller暗示的那样,你不希望在_OtherSize == _Size
时应用第一个构造函数,因为编译器生成的复制构造函数具有理想的行为。对于相同大小的Vector
,所述构造函数已经不如复制构造函数那么专业化,因此无论如何都不会在重载决策期间选择它,但最好通过切换<=
来明确目标。到<
。
答案 1 :(得分:4)
不要使用_Cap
;它们是为实施而保留的。实际上,std源使用tgese名称,因为它们是保留的。不要模仿std / system header内部命名约定。
template <size_t O>
Vector(const Vector<O>& v) : Vector()
{
constexpr auto to_copy = (std::min)( O, Size );
constexpr auto to_fill = Size-to_copy;
auto const* src=v.data();
std::copy(src, src + to_copy, _data);
std::fill(_data + to_copy, _data + to_copy+to_fill, 0.0);
}
Vector(const Vector& v) = default;
你会发现这可以优化你想要的代码;在无填充的情况下,使用std::fill
调用(foo, foo, 0.0)
,并且thr body是一个循环,当两次传递相同的指针时,编译器很容易证明这是一个noop。