访问成员变量中的引用会丢弃constness

时间:2015-06-18 12:40:05

标签: c++ c++11 reference compiler-errors const

我在我的代码中围绕一个对象创建了一个包装器,它应该修改对该对象的访问。我选择在这里使用一个对象进行测试,而不是一个具有相同功能的仿函数。基本上:包装器接收对象的引用并转发对象的所有索引访问(在一些可能的操作之后)
现在出现了问题:访问器丢弃了包装对象的常量。
最小例子

struct Foo
{
    std::array<int, 2> data;
    const int& operator()(int idx) const{
        return data[idx];
    }
    int& operator()(int idx){
        return data[idx];
    }
};

struct Bar
{
    Foo& ref;
    Bar(Foo& r):ref(r){}
    int& operator()(int idx) const{
        return ref(idx);
    }
};

template< typename T >
void test(const T& data){
    data(1) = 4;
    std::cout << data(1);
}

void main(){
    Foo f;
    test(f);
    // Above call does not compile (as expected)
    // (assignment of read-only location)
    Bar b(f);
    test(b); // This does compile and works (data is modified)
}

声明Bar(包装器)“const”的() - 操作符,我希望所有成员访问“const”到。所以不应该返回“int&amp;”但只有“const int&amp;”

然而,gcc4.7很乐意编译代码并忽略const。这是正确的行为吗?这是指定的位置?

编辑: 在相关问题上:如果在Foo中使用typedef,如:

struct Foo
{
    using Ref = int&;
    using ConstRef = const int&; //1
    using ConstRef = const Ref;  //2
    int* data; // Use int* to have same issue as with refs
    ConstRef operator()(int idx) const{
        return data[idx]; // This is possible due to the same "bug" as with the ref in Bar
    }
    Ref operator()(int idx){
        return data[idx];
    }
};

我注意到// 1确实按预期工作但// 2没有。返回值仍可修改。它们不应该是一样的吗?

2 个答案:

答案 0 :(得分:7)

是的,这是正确的行为。 ref的类型为Foo &。将const添加到引用类型 1 什么都不做 - 无论如何,引用已经是不可变的。这就像成员int *p一样。在const成员函数中,其类型被视为int * const p,而不是int const * p

您需要做的是在const重载内手动添加const,如果您需要它:

struct Bar
{
    Foo& ref;
    Bar(Foo& r):ref(r){}
    int& operator()(int idx) const{
        return const_cast<const Foo&>(ref)(idx);
    }
};

要解决编辑问题:不,typedef不一样。 const int &是对(常量int)的引用。 const Ref是常量Ref,即常量(对int的引用);数学意义上使用的括号。

1 我在谈论参考类型本身。不要将const添加到引用所引用的类型。

答案 1 :(得分:1)

是的,这是预期的行为。原因是你的方法的const只表示引用不会改变而不是引用的对象。参考始终保持不变,因此始终如此。用指针看看这段代码:

int i;
struct Bar
{
    int* pi;
    Foo& ref;
    Bar(Foo& r):ref(r){}
    int& operator()(int idx) const{
        *pi = 4; // we can change pointed object
        pi = &i; // Compile error: we can't change the pointer.
        return ref(idx);
    }
};