从const和返回迭代器的非const方法中删除代码重复

时间:2013-01-21 19:45:12

标签: c++ const dry

我在const和非const类方法上考虑this question。首选答案取自Scott Meyers的Effective C ++,其中非const方法是根据const方法实现的。

进一步扩展,如果方法返回迭代器而不是引用,如何减少代码重复?修改链接问题中的示例:

class X
{
    std::vector<Z> vecZ;    
public:
    std::vector<Z>::iterator Z(size_t index)
    {
        // ...
    }
    std::vector<Z>::const_iterator Z(size_t index) const
    {
        // ...
    }
};

我无法在const方法方面实现非const方法,因为不使用distance()/ advance()技术就无法直接从const_iterator转换为迭代器。

在这个例子中,因为我们使用std :: vector作为容器,所以实际上可以从const_iterator转换为迭代器,因为它们很可能被实现为指针。我不想依赖于此。有更普遍的解决方案吗?

3 个答案:

答案 0 :(得分:5)

你可以使用几种技巧。 You can turn a const_iterator into an iterator if you have non-const access to the container.(你这样做):

std::vector<Z>::iterator Z(size_t index)
{
    std::vector<Z>::const_iterator i = static_cast<const X&>(*this).Z(index);
    return vecZ.erase(i, i);
}

你也可以这样做:

std::vector<Z>::iterator Z(size_t index)
{
    return std::next(vecZ.begin(), std::distance(vecZ.cbegin(), static_cast<const X&>(*this).Z(index)));
}

两者都不是特别优雅。为什么我们没有像const_iterator_cast这样的const_pointer_cast?也许我们应该。

编辑,我错过了最明显和最优雅的解决方案,因为我试图使用非const方法的const方法。在这里我做了相反的事情:

std::vector<Z>::const_iterator Z(size_t index) const
{
    return const_cast<X&>(*this).Z(index);
}

您正在取消引用const_cast的结果,但只要非const Z不修改X中的任何数据,这不是未定义的行为。与我给出的其他两个解决方案不同,这是我可能在实践中使用的解决方案。

答案 1 :(得分:2)

我相信,只有助手

才有可能
typedef int Z;

class X
{
    std::vector<Z> vecZ;    
public:
    std::vector<Z>::iterator foo(size_t index)
    {
        return helper(*this);
    }
    std::vector<Z>::const_iterator foo(size_t index) const
    {
        return helper(*this);
    }

    template <typename T>
    static auto helper(T& t) -> decltype(t.vecZ.begin())
    {
        return t.vecZ.begin();
    }
};

修改 可以在没有c ++ 11的情况下实现相同的

template <typename T>
struct select
{
    typedef std::vector<Z>::iterator type;
};
template <typename T>
struct select<const T&>
{
    typedef std::vector<Z>::const_iterator type;
};

template <typename T>
static
typename select<T>::type
helper(T t) 
{
    return t.vecZ.begin();
}

但是,我认为你在使用这个approcach之前应该三思而后

答案 2 :(得分:1)

如果您正在使用C ++ 11,那么有一种更优雅的(IMHO)方式,它在模板迭代器类中仅使用两个typedef来区分const和常规迭代器:   http://www.sjvs.nl/c-implementing-const_iterator-and-non-const-iterator-without-code-duplication/