为什么无法识别我重载的乘法运算符?
Why is my overloaded multiplication operator not recognized?
为什么以下代码会产生编译器错误 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;
}
代码失败,因为 x
是一个左值引用,您不能对其应用 ::
访问运算符。为此,您应该首先 std::decay_t
推导类型 E
,即写
typename std::decay_t<E>::value_type
您有两个重载 operator*
是(暂时忽略 return 类型):
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<std::array<double, 3>>&
。请注意,它是 reference。因此,没有 E::value_type
因为它是引用类型。您必须先删除该部分(对于两个重载)。最简单的方法是引入第二个默认模板参数,它是 un 引用版本的 E
:
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
没有构造函数。但这是一个不相关的问题。
为什么以下代码会产生编译器错误 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;
}
代码失败,因为 x
是一个左值引用,您不能对其应用 ::
访问运算符。为此,您应该首先 std::decay_t
推导类型 E
,即写
typename std::decay_t<E>::value_type
您有两个重载 operator*
是(暂时忽略 return 类型):
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<std::array<double, 3>>&
。请注意,它是 reference。因此,没有 E::value_type
因为它是引用类型。您必须先删除该部分(对于两个重载)。最简单的方法是引入第二个默认模板参数,它是 un 引用版本的 E
:
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
没有构造函数。但这是一个不相关的问题。