为什么没有标准化的方法来避免const方法代码重复?

w1t*_*am3 7 c++

根据我的经验,在const和非const版本的成员方法中使用相同的代码是一种常见的现象.避免复杂方法的代码重复的一种方法是使用a const_cast去除非const版本中的常量,如在Effective C++(第3项)中推荐的Scott Meyers.然而,这对于可能只返回指针的非常短的方法是没有益处的 - 当然,在这种情况下复制不是那么有问题.这仍然让我想知道是否存在没有关键字或等效替换铸件的原因.我可以想象使用以下声明:

autoconst Data* const getData() autoconst;
Run Code Online (Sandbox Code Playgroud)

当然这个关键字不会添加任何以前无法实现的功能,但我认为它会很好.据我所知,auto关键字同样不允许任何新的结构,但在代码中是一个很好的简化 - 不可否认的是更广泛(如果我错了请纠正我).

我的问题是这是否与C++标准中的某些规则相冲突 - 如果不是,它是否只是没有用到实现.

Ben*_*igt 5

有一种标准化的方式,但没有多少人使用它:

class X
{
    T data;
public:
    template<typename autoconst>
    friend /* or static */ auto get_data(autoconst& that) -> decltype(that.data)
    {
        // process that and return that.data
    }
};
Run Code Online (Sandbox Code Playgroud)

它被称为get_data(x),而不是x.get_data(),而是一个实现符合两国const和非const使用,而无需进行转换或其他非类型安全的技术.

还可以使用成员函数来启用成员调用语法.这将需要const和非const变体,但没有"过程that.data"步骤的重复,因为两者都可以委托给朋友模板.

更完整的例子:

template<typename T>
class HyperMatrix
{
    int rows, cols, planes;
    T* data;
    /* they get initialized somehow */

public:
    template<typename ThisType>
    friend /* or static */ auto at(ThisType& that, int const r, int const c, int const p) -> decltype(*(that.data))
    {
        // argument validation logic not being duplicated
        if (r < 0 || r >= that.rows) throw index_exception();
        if (c < 0 || c >= that.cols) throw index_exception();
        if (p < 0 || p >= that.planes) throw index_exception();
        // complicated indexing expression, also not duplicated
        const index = (p * that.rows + r) * that.cols + c;
        return that.data[index];
    }

    // these enable a more natural syntax than at(hymatrix, 1, 2, 3)
    T& operator()(int const r, int const c, int const p)
    { return /* ThisType = HyperMatrix<T> */ at(this, r, c, p); }

    const T& operator()(int const r, int const c, int const p)
    { return /* ThisType = const HyperMatrix<T> */ at(this, r, c, p); }
};
Run Code Online (Sandbox Code Playgroud)

示例没有简单的解决方法:

template<typename T>
class BalancedJumpTable
{
public:
    template<typename ThisType, typename Functor>
    friend /* or static */ auto for_each(ThisType& that, Functor f)
    {
        // complicated code for walking the tree not duplicated
        // deep inside loops and recursive calls, we find
           f(that->something());
        // maybe there's even some filtering logic which causes only
        // only certain items to be passed to the callback
    }

    template<typename Functor>
    void for_each(Functor f)
    { return for_each(this, f); }

    void for_each(Functor f) const
    { return for_each(this, f); }
};
Run Code Online (Sandbox Code Playgroud)


Bli*_*ndy -3

我不会满足你的需要。事实上,如果您发现自己反复抛弃,我并不认为您的代码从一开始就是完全正确的const

考虑一下您可以将非const对象传递给需要const对象的函数。const参数上的 仅仅是一个约定,即被调用者不会更改对象——要么更改,要么不更改。如果它确实改变了它,那么传递一个const对象就是一个错误(其错误是有争议的,但在某个地方有错误)。如果它不改变它,你可以通过任何东西。

我不知道除了尝试用正确的合约重写你的代码之外还能说什么,或者如果你不介意的话,根本不使用任何合约const

  • 我认为您没有正确理解我的问题。我正在谈论一个返回指针(例如在容器中)并使用 const 版本和非 const 版本重载的成员方法。通常它们的作用完全相同,并且代码可能很复杂。因此,如果您不通过放弃 const 版本的 constness 来实现非 const 版本,这会导致代码重复。 (5认同)
  • @Blindy:你完全忽略了_返回值_,它有时是“const”,有时不是“const”。例如,查看 `vector::operator[]` 和 `vector::at` 以及 `vector::back` 和 `vector::front` 以及 `vector::begin` 和 `vector::end` 和 ` vector::data`.,它们都有OP正在讨论的相同问题。 (3认同)