重载运算符时原子约束''的满足取决于自身和ICE*

问题描述 投票:0回答:0

我想创建可与 mp-units 一起使用的自定义 Vector 类,但我无法创建

operator*()
和 `operator*()。我在 godbolt 上重现了问题:https://godbolt.org/z/sMbxccMev 这里是有问题的代码:

#include "units/isq/si/length.h"
#include "units/isq/si/area.h"
#include "units/math.h"

#include <iostream>

template<units::Quantity quantity>
struct Vector
{
    quantity x;
    quantity y;

    Vector& operator+=(const Vector& rhs)
    {
        x += rhs.x;
        y += rhs.y;
        return *this;
    }

    friend Vector operator+(Vector lhs,
                       const Vector& rhs)
    {
        lhs += rhs;
        return lhs;
    }

    Vector& operator-=(const Vector& rhs)
    {
        x -= rhs.x;
        y -= rhs.y;
        return *this;
    }
    friend Vector operator-(Vector lhs,
                              const Vector& rhs)
    {
        lhs -= rhs;
        return lhs;
    }


    [[nodiscard]] Vector<units::dimensionless<units::one>> normalized() const
    {
        return {x/norm(),y/norm()};
    }
    [[nodiscard]] decltype(std::declval<quantity>()*std::declval<quantity>()) norm_squared() const
    {
        return x * x + y * y;
    }
    [[nodiscard]] quantity norm() const
    {
        return units::sqrt(norm_squared());
    }

    [[nodiscard]] quantity distanceTo(const Vector& other) const
    {
        return (other - *this).norm();
    }

};
template<units::Quantity vector_quantity, typename S>
auto operator*(Vector<vector_quantity> lhs, const S& rhs)
{
    auto tmp_x =  lhs.x * rhs;
    auto tmp_y =  lhs.y * rhs;
    return Vector{tmp_x,tmp_y};
}

template<units::Quantity vector_quantity, typename scalar>
auto operator/(Vector<vector_quantity> lhs,
               const scalar & rhs) -> Vector<decltype(std::declval<vector_quantity>()/std::declval<scalar>())>
{
    Vector<decltype(std::declval<vector_quantity>()/std::declval<scalar>())> tmp;
    tmp.x =  lhs.x / rhs;
    tmp.y =  lhs.y / rhs;
    return tmp;
}
int main()
{
    using namespace units::isq::si::references;
    auto some_val = 2 * m;
    Vector<units::isq::si::length<units::isq::si::metre>> some_vector{2 * m, 2 * m};
    auto other = some_vector.normalized(); // should be Vector<units::dimensionless<units::one>>
    std::cout << std::boolalpha << std::is_same<decltype(other), Vector<units::dimensionless<units::one>>>::value;
    auto another = other * some_val; // should be Vector<units::isq::si::length<units::isq::si::metre>> again
    std::cout << std::boolalpha << std::is_same<decltype(another), Vector<units::isq::si::length<units::isq::si::metre>>>::value;

}

和错误信息:

In file included from /opt/compiler-explorer/libs/mp-units/v0.7.0/src/core/include/units/bits/external/hacks.h:81,
                 from /opt/compiler-explorer/libs/mp-units/v0.7.0/src/core/include/units/bits/basic_concepts.h:25,
                 from /opt/compiler-explorer/libs/mp-units/v0.7.0/src/core/include/units/concepts.h:26,
                 from /opt/compiler-explorer/libs/mp-units/v0.7.0/src/systems/isq/include/units/isq/dimensions/length.h:25,
                 from /opt/compiler-explorer/libs/mp-units/v0.7.0/src/systems/si/include/units/isq/si/length.h:26,
                 from <source>:1:
/opt/compiler-explorer/gcc-11.3.0/include/c++/11.3.0/bits/stl_function.h: In substitution of 'template<class Value>  requires !(Quantity<Value>) && (invoke_result_convertible_to_<Rep, std::multiplies<void>, const Value&, Rep>) constexpr auto [requires units::Quantity<<placeholder>, >] units::operator*(const Value&, const units::quantity<units::dim_one, units::one, double>&) [with Value = units::dim_one]':
/opt/compiler-explorer/gcc-11.3.0/include/c++/11.3.0/bits/stl_function.h:281:37:   required by substitution of 'template<class _Tp, class _Up> constexpr decltype ((forward<_Tp>(__t) * forward<_Up>(__u))) std::multiplies<void>::operator()(_Tp&&, _Up&&) const [with _Tp = const Vector<units::quantity<units::dim_one, units::one, double> >&; _Up = double]'
/opt/compiler-explorer/gcc-11.3.0/include/c++/11.3.0/type_traits:2536:26:   required by substitution of 'template<class _Fn, class ... _Args> static std::__result_of_success<decltype (declval<_Fn>()((declval<_Args>)()...)), std::__invoke_other> std::__result_of_other_impl::_S_test(int) [with _Fn = std::multiplies<void>; _Args = {const Vector<units::quantity<units::dim_one, units::one, double> >&, double}]'
/opt/compiler-explorer/gcc-11.3.0/include/c++/11.3.0/type_traits:2547:55:   required from 'struct std::__result_of_impl<false, false, std::multiplies<void>, const Vector<units::quantity<units::dim_one, units::one, double> >&, double>'
/opt/compiler-explorer/gcc-11.3.0/include/c++/11.3.0/type_traits:2552:12:   required from 'struct std::__invoke_result<std::multiplies<void>, const Vector<units::quantity<units::dim_one, units::one, double> >&, double>'
/opt/compiler-explorer/gcc-11.3.0/include/c++/11.3.0/type_traits:3013:12:   [ skipping 4 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/opt/compiler-explorer/gcc-11.3.0/include/c++/11.3.0/type_traits:2536:26:   required by substitution of 'template<class _Fn, class ... _Args> static std::__result_of_success<decltype (declval<_Fn>()((declval<_Args>)()...)), std::__invoke_other> std::__result_of_other_impl::_S_test(int) [with _Fn = std::multiplies<void>; _Args = {const Vector<units::quantity<units::dim_one, units::one, double> >&, int}]'
/opt/compiler-explorer/gcc-11.3.0/include/c++/11.3.0/type_traits:2547:55:   required from 'struct std::__result_of_impl<false, false, std::multiplies<void>, const Vector<units::quantity<units::dim_one, units::one, double> >&, int>'
/opt/compiler-explorer/gcc-11.3.0/include/c++/11.3.0/type_traits:3013:12:   recursively required by substitution of 'template<class _Result, class _Ret> struct std::__is_invocable_impl<_Result, _Ret, true, std::__void_t<typename _CTp::type> > [with _Result = std::__invoke_result<std::multiplies<void>, const Vector<units::quantity<units::dim_one, units::one, double> >&, int>; _Ret = void]'
/opt/compiler-explorer/gcc-11.3.0/include/c++/11.3.0/type_traits:3013:12:   required from 'struct std::is_invocable<std::multiplies<void>, const Vector<units::quantity<units::dim_one, units::one, double> >&, int>'
/opt/compiler-explorer/gcc-11.3.0/include/c++/11.3.0/type_traits:3260:71:   required from 'constexpr const bool std::is_invocable_v<std::multiplies<void>, const Vector<units::quantity<units::dim_one, units::one, double> >&, int>'
/opt/compiler-explorer/gcc-11.3.0/include/c++/11.3.0/concepts:336:25:   required by substitution of 'template<class Value>  requires !(Quantity<Value>) && (invoke_result_convertible_to_<Rep, std::multiplies<void>, const Value&, Rep>) constexpr auto [requires units::Quantity<<placeholder>, >] units::operator*(const Value&, const units::quantity<units::isq::si::dim_length, units::isq::si::metre, int>&) [with Value = units::isq::si::dim_length]'
<source>:84:28:   required from here
/opt/compiler-explorer/gcc-11.3.0/include/c++/11.3.0/concepts:336:13:   required for the satisfaction of 'invocable<_Fn, _Args ...>' [with _Fn = std::multiplies<void>; _Args = {const Vector<units::quantity<units::dim_one, units::one, double> >&, double}]
/opt/compiler-explorer/gcc-11.3.0/include/c++/11.3.0/concepts:340:13:   required for the satisfaction of 'regular_invocable<Func, T, U>' [with Func = std::multiplies<void>; U = double; T = const Vector<units::quantity<units::dim_one, units::one, double> >&]
/opt/compiler-explorer/libs/mp-units/v0.7.0/src/core/include/units/quantity.h:77:9:   required for the satisfaction of 'quantity_value_for_<Func, U, V>' [with Func = std::multiplies<void>; U = const Vector<units::quantity<units::dim_one, units::one, double> >&; V = double]
/opt/compiler-explorer/libs/mp-units/v0.7.0/src/core/include/units/quantity.h:82:9:   required for the satisfaction of 'invoke_result_convertible_to_<Rep, std::multiplies<void>, const Value&, Rep>' [with Value = Vector<units::quantity<units::dim_one, units::one, double> >; Rep = double]
/opt/compiler-explorer/gcc-11.3.0/include/c++/11.3.0/concepts:336:25: error: satisfaction of atomic constraint 'is_invocable_v<_Fn, _Args ...> [with _Fn = std::multiplies<void>; _Args = {const Value&, Rep}]' depends on itself
  336 |     concept invocable = is_invocable_v<_Fn, _Args...>;
      |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'
Internal compiler error: Error reporting routines re-entered.
0x178854d error_at(unsigned int, char const*, ...)
    ???:0
0x6be0a2 satisfaction_cache::get()
    ???:0
0x6c2a6a constraints_satisfied_p(tree_node*, tree_node*)
    ???:0
0x7f4597 fn_type_unification(tree_node*, tree_node*, tree_node*, tree_node* const*, unsigned int, tree_node*, unification_kind_t, int, conversion**, bool, bool)
    ???:0
0x6924f0 build_new_op(op_location_t const&, tree_code, int, tree_node*, tree_node*, tree_node*, tree_node**, int)
    ???:0
0x82b7ed build_x_binary_op(op_location_t const&, tree_code, tree_node*, tree_code, tree_node*, tree_code, tree_node**, int)
    ???:0
0x7da35d tsubst(tree_node*, tree_node*, int, tree_node*)
    ???:0
0x1793bf2 pp_format(pretty_printer*, text_info*)
    ???:0
0x1794240 pp_format_verbatim(pretty_printer*, text_info*)
    ???:0
0x1794321 pp_verbatim(pretty_printer*, char const*, ...)
    ???:0
0x17873bd diagnostic_report_diagnostic(diagnostic_context*, diagnostic_info*)
    ???:0
0x178854d error_at(unsigned int, char const*, ...)
    ???:0
0x6be0a2 satisfaction_cache::get()
    ???:0
0x6c2a6a constraints_satisfied_p(tree_node*, tree_node*)
    ???:0
0x7f4597 fn_type_unification(tree_node*, tree_node*, tree_node*, tree_node* const*, unsigned int, tree_node*, unification_kind_t, int, conversion**, bool, bool)
    ???:0
0x6924f0 build_new_op(op_location_t const&, tree_code, int, tree_node*, tree_node*, tree_node*, tree_node**, int)
    ???:0
0x82b7ed build_x_binary_op(op_location_t const&, tree_code, tree_node*, tree_code, tree_node*, tree_code, tree_node**, int)
    ???:0
0x7d9bb8 maybe_instantiate_noexcept(tree_node*, int)
    ???:0
0x6929d3 build_op_call(tree_node*, vec<tree_node*, va_gc, vl_embed>**, int)
    ???:0
0x8082c2 finish_call_expr(tree_node*, vec<tree_node*, va_gc, vl_embed>**, bool, bool, int)
    ???:0
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.

有趣的是

operator/()
曾经在不同版本的库(或者更确切地说是不同的包管理 - 以前是 FetchContent_Declare,现在是 Conan)上处理 msvc,但我无法确定确切的版本。
operator*()
尝试修复。

c++ c++20 units-of-measurement
© www.soinside.com 2019 - 2024. All rights reserved.