【问题标题】:Use universal reference for operator= instead of multiple overloads对 operator= 使用通用引用而不是多个重载
【发布时间】:2020-06-15 09:30:49
【问题描述】:

有一个简单的包装结构

template<typename T>
struct named_value {
    using type = T;
    T value{};
    string_view name = "unnamed_value";

    constexpr explicit operator T&(){ return value; }
    constexpr explicit operator T const&()const{ return value; }
    constexpr explicit operator T &&()&&{ return std::move(value); }

    template<typename U=T>
    constexpr named_value& operator=(U&&v){ value = std::forward<U>(v); return *this; }

    friend auto operator<<(std::ostream& os, named_value const& a) ->ostream&
    {
        return os<<a.name<<":"<<a.value;
    }
};

在这里,我尝试对operator= 使用通用引用,以减少重载(即for ref、rval ref、const ref)。这是正确的方法吗?

【问题讨论】:

  • named_value& - 已修复
  • 感谢您删除 cmets。
  • 返回 *this。固定
  • It should beoperator T&amp;&amp;() &amp;&amp; { return std::move(value); }.
  • @Evg,谢谢,已修复

标签: c++


【解决方案1】:

这是一个有问题的实现。问题是它可能会干扰常规分配。编译器会为您生成operator=(name_value const&amp;v),并通过 const 引用获取。但是当源对象是非常量时,模板特化生成的重载会变得更好。

比如这段代码

named_value<int> a;
a = a;

使用 GCC 产生此错误

main.cpp: In instantiation of 'constexpr named_value<T>& named_value<T>::operator=(U&&) [with U = named_value<int>&; T = int]':
main.cpp:18:10:   required from here
main.cpp:13:51: error: cannot convert 'named_value<int>' to 'int' in assignment
   13 |     constexpr named_value& operator=(U&&v){ value = std::forward<U>(v); return *this; }

你需要用 SFINAE 来对付它。所以,如果我们说可能去编译器产生的重载的东西应该被拒绝。那么……

template<typename U=T, std::enable_if_t< !std::is_convertible_v<U&&, named_value> , int> = 0>
constexpr named_value& operator=(U&&v){ value = std::forward<U>(v); return *this; }

或者,如果使用 C++20

template<typename U=T> requires (!std::convertible_to<U&&, named_value>)
constexpr named_value& operator=(U&&v){ value = std::forward<U>(v); return *this; }

您当然可以选择其他检查,例如 std::is_same 或 std::same_as,具体取决于您希望实现的确切语义。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多