【问题标题】:Why does my templated operator== not get used?为什么我的模板化 operator== 不被使用?
【发布时间】:2016-07-28 14:10:26
【问题描述】:

我定义operator==如下:

template <class State>
bool operator==(const std::shared_ptr<const State> &lhs,
                const std::shared_ptr<const State> &rhs) {
    return *lhs == *rhs;
}

此运算符未实例化(在gdb 中,我无法在返回语句上设置断点——该行不存在)。

但是,这个操作符应该被这行调用的std::find使用:

return std::find(v.begin(), v.end(), el) != v.end();

我在gdb的上面一行中检查了v的类型:

(gdb) whatis v
type = const std::vector<std::shared_ptr<Domains::IncWorst const>> &
(gdb) whatis el
type = const std::shared_ptr<Domains::IncWorst const> &

这不符合我的模板化 operator==StateIncWorst 吗?

我实现了一个如下的玩具示例并且示例有效,所以我不明白为什么真正的代码没有。

template<class V, typename T>
bool in(const V &v, const T &el) {
    return std::find(v.begin(), v.end(), el) != v.end();
}

struct MyState {
    MyState(int xx) : x(xx) {}
    bool operator==(const MyState &rhs) const {
        return x == rhs.x;
    }
    int x;
};

template <class State>
bool operator==(const std::shared_ptr<const State> &lhs,
                const std::shared_ptr<const State> &rhs) {
    return *lhs == *rhs;
}

int main() {
    std::vector<std::shared_ptr<const MyState>> v{
        std::make_shared<const MyState>(5)};
    auto p = std::make_shared<const MyState>(5);
    std::cout << in(v, p) << std::endl; // outputs 1
    return 0;
}

【问题讨论】:

  • 只是一个猜测,但您确定该模板在您调用 find 的文件中可供编译器使用吗?换句话说,它是#included 还是定义在该文件的顶部?
  • 确实如此。我检查了预处理器的输出以确保。
  • 这似乎是解决问题的错误方法。无需为您的一个用例定义全局 == 运算符,只需将 lambda 比较器传递给 std::find_if。不过,仍然对这不起作用的技术原因感到好奇。
  • 令我感兴趣的是,您在全局命名空间中的operator==std 命名空间中定义的operator== 具有几乎 相同的函数签名-- std operator== 用于 both 参数上的 shared_ptr 模板,并且没有用于 shared_ptrs 的 const 模板参数。不过,我在这个上使用了 templatetypedef:不要创建适用于所有 shared_ptr 类型的全局函数,请指明您想要哪种相等。默认的将被假定为您的代码的所有读者都使用的那个。我会使用 owner_lesseq 版本
  • @templatetypedef 我有很多代码依赖于测试相等性共享指向 const 状态的指针。我不想将它全部更改为使用 lambdas。当然,我会在未来让这个模板更加精确,只捕获状态,而不是过多地污染全局命名空间。

标签: c++ templates operator-overloading


【解决方案1】:

您的 operator== 模板位于错误的命名空间中。

为了被 ADL 找到,它必须位于 std 命名空间(这将是非法的,根据 [namespace.std]/1)或 Domains(根据 [basic.lookup.argdep]/2)。

但是,这仍然是非常危险的,因为如果在声明 operator== 模板之前和之后实例化任何执行相等比较的模板(例如但不限于 std::find),那么您的整个程序将无效[temp.point]/8[basic.def.odr]/6

如果您必须为您的类型的std::shared_ptrs 提供运算符重载模板,最好在声明每个类之后显式实例化它们,这样模板在某处被实例化的机会就会减少该类不可见:

struct MyState {
    // ...
};
template bool operator==<MyState>(
    const std::shared_ptr<MyState const>&,
    const std::shared_ptr<MyState const>&);

如果有人在其他地方前向声明 MyState,这可能仍然存在问题,但这可能是您能做的最好的事情。

【讨论】:

  • 你是对的!如果我将 MyState 在我的玩具示例中放入它自己的命名空间中,该示例将停止工作!
  • 至于首选的解决方案,如何使用派生自std::shared_ptr&lt;T&gt; 的类型来定义operator==
  • @AlwaysLearning 是的,没关系。封装std::shared_ptr&lt;T&gt;(即,将其作为数据成员)会更安全,因为这样您可以完全控制运算符和转换。
猜你喜欢
  • 2021-03-16
  • 2019-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-20
相关资源
最近更新 更多