5

我有一个成员变量std::set<T*> m_associates;,即非常量原始指针的集合,并且只想检查是否存在另一个指针。为了保持 const 正确性,我的函数如下所示:

bool MyClass::is_associated(const T* x) const
{
    return (m_associates.find(x) != m_associates.end());
}

但是,这不会编译,因为x传递 asconst T*表示指向的值x没有被函数更改,而是m_associates包含非常量T*

如果我constx参数中删除,它会编译,但违反 const 正确性......

添加constm_associatesiestd::set<const T*> m_associates;也不是一个选项,因为我需要类中其他地方的非常量指针。

我该如何解决这个问题?这是(可能是唯一的)const_cast应该使用 a 的地方吗?还是我必须始终将所有参数T指针作为非常量传递?

编辑:完整的错误输出,编译器是 clang++-8,代码是 C++17

error: no matching member function for call to 'find'
        return (m_associates.find(x) != m_associates.end());
                ~~~~~~~~~~~~^~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_set.h:798:7: note: candidate function not viable: 1st argument ('const T *') would lose const qualifier
      find(const key_type& __x) const
      ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_set.h:804:2: note: candidate function template not viable: 'this' argument has type 'const std::set<T *>', but method is not marked const
        find(const _Kt& __x)
        ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_set.h:794:7: note: candidate function not viable: 'this' argument has type 'const std::set<T *>', but method is not marked const
      find(const key_type& __x)
      ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_set.h:810:2: note: candidate template ignored: substitution failure [with _Kt = const T *]: no matching member function for call to '_M_find_tr'
        find(const _Kt& __x) const
        ^
4

2 回答 2

10

您当前代码失败的原因是默认Compare为; 这迫使两个参数都是用于比较的——在这种情况下,是非类型。由于不能在不抛弃常量的情况下转换为,这会导致您的编译错误。std::set<T>std::less<T>Tconst T*const T*T*

如果您使用的是 C++14 或更高版本,则可以重新定义您std::set的模板类型,以便Compare模板类型是一个透明的比较器(用于推断底层类型进行比较的比较器),例如std::set<T*, std::less<>>. 这将启用std::set::find推断类型并将参数转发给比较器的重载,这将使上述代码能够工作。

于 2020-08-11T13:21:17.887 回答
4

在这种情况下,你可以抛弃没有不良影响的const-ness 。x

除了可能表示设计缺陷之外,您唯一需要注意的const是,尝试修改最初const通过非const指针声明使用的对象时的行为是未定义的。这不是这里的情况。

于 2020-08-11T13:20:10.667 回答