【问题标题】:Why is my overloaded multiplication operator not recognized?为什么我的重载乘法运算符无法识别?
【发布时间】:2016-04-09 17:53:24
【问题描述】:

为什么下面的代码会产生编译器错误no match for operator*

template<class E>
class vector_expression {};

template<class Tuple>
class vector
    : public vector_expression<vector<Tuple>>
{
public:
    using value_type = typename Tuple::value_type;
};

namespace detail
{
    template<typename T>
    class scalar
        : public vector_expression<scalar<T>>
    {};
}

template<class E1, class E2, class BinaryOperation>
class vector_binary_operation
    : public vector_expression<vector_binary_operation<E1, E2, BinaryOperation>>
{
public:
    template<class F1, class F2>
    vector_binary_operation(F1&& e1, F2&& e2, BinaryOperation op)
        : m_e1(std::forward<F1>(e1)), m_e2(std::forward<F2>(e2)),
          m_op(std::move(op))
    { }

private:
    E1 m_e1;
    E2 m_e2;
    BinaryOperation m_op;
};

template<class E>
vector_binary_operation<detail::scalar<typename E::value_type>, E, std::multiplies<>> operator*(typename E::value_type value, E&& e) {
    return { std::move(value), std::forward<E>(e), std::multiplies<>{} };
}
template<class E>
vector_binary_operation<E, detail::scalar<typename E::value_type>, std::multiplies<>> operator*(E&& e, typename E::value_type value) {
    return { std::forward<E>(e), std::move(value), std::multiplies<>{} };
}

int main()
{
    vector<std::array<double, 3>> x;
    3 * x;

    return 0;
}

DEMO

【问题讨论】:

  • 您的“DEMO”链接对我不起作用。
  • 仅供参考,3int,而不是 double。模板对这类东西很敏感。
  • @MartinBonner 抱歉,已解决。
  • @Cornstalks 这不是重点。如果将3 替换为3.,它仍然不起作用。
  • 我想我只需要使用typename std::decay_t&lt;E&gt;::value_type 而不是typename E::value_type

标签: c++ templates operator-overloading c++14 c++17


【解决方案1】:

您有两个重载的operator*(暂时忽略返回类型):

template <class E>
R operator*(typename E::value_type, E&& );

template <class E>
R operator*(E&&, typename E::value_type );

在这两种情况下,一个参数是非推导上下文。让我们从第二个重载开始。当我们用3 * x调用时,E被推导出为int,没有int::value_type,所以是替换失败。

在第一个重载中,我们将E 推断为vector&lt;std::array&lt;double, 3&gt;&gt;&amp;。请注意,它是一个参考。因此,没有E::value_type,因为它是一个引用类型。您必须首先删除该部分(对于两个重载)。最简单的方法是引入第二个默认模板参数,它是Eun引用版本:

template<class E, class ER = std::remove_reference_t<E>>
vector_binary_operation<detail::scalar<typename ER::value_type>, ER, std::multiplies<>>
operator*(typename ER::value_type value, E&& e);

通过该修复,现在您的代码由于不同的原因无法编译:scalar 没有构造函数。但这是一个不相关的问题。

【讨论】:

  • decay 打字更短(而且它执行的额外转换是无害的)
  • 你说得对,我刚刚注意到我忘记写 std::decay_t&lt;E&gt; 而不是 E
  • @T.C.它更短,但我有时更喜欢remove_reference,因为我们实际上只是删除了一个引用。
【解决方案2】:

代码失败,因为x 是一个左值引用,您不能在其上应用:: 访问运算符。为此,您应该首先std::decay_t推导类型E,即写

typename std::decay_t<E>::value_type

【讨论】:

    猜你喜欢
    • 2020-08-25
    • 1970-01-01
    • 2015-01-15
    • 1970-01-01
    • 2022-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-18
    相关资源
    最近更新 更多