【问题标题】:Have two different versions of arrow operator?有两个不同版本的箭头运算符?
【发布时间】:2017-06-09 15:43:57
【问题描述】:

我有以下用于锁定对象的类:

#include <memory>

template <class Type, class Mutex>
class LockableObject {
 public:
  class UnlockedObject {
   public:
    UnlockedObject(Mutex &mutex, Type &object)
        : mutex_(mutex), object_(object) {}
    UnlockedObject(UnlockedObject &&other) = default;

    // No copying allowed
    UnlockedObject(const UnlockedObject &) = delete;
    UnlockedObject &operator=(const UnlockedObject &) = delete;

    ~UnlockedObject() { mutex_.unlock(); }

    Type *operator->() { return &object_; }   // Version 1
    // Type &operator->() { return object_; } // Version 2


   private:
    Mutex &mutex_;
    Type &object_;
  };

  template <typename... Args>
  LockableObject(Args &&... args) : object_(std::forward<Args>(args)...) {}

  UnlockedObject Lock() {
    mutex_.lock();
    return UnlockedObject(mutex_, object_);
  }

 private:
  Mutex mutex_;
  Type object_;
};

我想按如下方式使用它来锁定和解锁对共享对象的访问。第二个示例利用了-&gt; 运算符多次应用自身的能力:

  // Example 1
  {
    LockableObject<std::string, std::mutex> locked_string;
    auto unlocked_string = locked_string.Lock();
    // This is what I want:
    unlocked_string->size(); // works for version 1, breaks for version 2
  }

  // Example 2
  {
    LockableObject<std::unique_ptr<std::string>, std::mutex> locked_string(std::unique_ptr<std::string>(new std::string()));
    auto unlocked_string = locked_string.Lock();
    // This is what I want:
    unlocked_string->size(); // works for version 2, breaks for Version 1

    // Workaround
    unlocked_string->get()->size(); // works for version 1, but is not nice
  }

能否以某种方式更改类以使两个示例都使用unlocked_string-&gt;size() 而不是使用-&gt;get() 的解决方法?可能通过使用模板专业化或类似的东西?

【问题讨论】:

  • 考虑LockablePtr类型?
  • 重载 operator() 以获得类似 unlocked_string()-&gt;size() 的内容。问题真的是你的get() 来自std::unique_ptr。如果您想摆脱get(),则必须专门为unique_pointer 设计模板
  • @subzero 专门用于unique_ptr,或者甚至更好,具有用于Types 的版本2 与重载operator-&gt; 和用于其他Types 的版本1 会很好...有关如何执行此操作的更多详细信息?

标签: c++ c++11 templates operator-overloading


【解决方案1】:

写入LockablePtrLockableValue 类型。

LockableObject 根据传入的类型有条件地选择上述哪一项。使用某种 SFINAE 或特征等检测智能指针。

此选择可以通过using 别名,或通过using 继承来获取父构造函数。

namespace details {
  template<template<class...>class, class, class...>
  struct can_apply : std::false_type {};
  template<class...>struct voider{using type=void;};
  template<class...Ts>using void_t=typename voider<Ts...>::type;
  template<template<class...>class Z, class...Ts>
  struct can_apply<Z, void_t<Z<Ts...>>, Ts...> : std::true_type {};
}
template<template<class...>class Z, class...Ts>
using can_apply = details::can_apply<Z, void, Ts...>;

template<class T>
using star_r = decltype( *std::declval<T>() );
template<class T>
using is_ptr_like = can_apply< star_r, T >;

is_ptr_like 是可以一元解引用的事物的特征。

假设你同时写了LockablePtr&lt;T,M&gt;LockableValue&lt;T,M&gt;

template<class T, class M>
using Lockable = 
  typename std::conditional< is_ptr_like<T&>::value,
    LockablePtr<T, M>,
    LockableValue<T, M>
  >::type;

template<class T, class M>
struct LockableObject:Lockable<T,M> {
  using Lockable<T,M>::Lockable;
};

完成了。

顺便说一句,您可以选择存储

Type&

看起来很糟糕。

【讨论】:

  • 非常感谢您的详细回答并帮助我指明了正确的方向!最后,我最终做了一些非常相似的事情。您能否详细说明为什么您认为存储 Type& 是一个坏主意?我需要它通过 UnlockedObject 类访问 object_...
  • @jan 第二次阅读没问题;我以为它在可锁定对象而不是未锁定对象中。
【解决方案2】:

感谢您的提示和回答。我最终使用以下方法来检测箭头运算符的存在:

template <class> struct type_sink { typedef void type; };  // consumes a type, and makes it `void`
template <class T> using type_sink_t = typename type_sink<T>::type;
template <class T, class = void> struct has_arrow : std::false_type {};
template <class T> struct has_arrow<T, type_sink_t<decltype(std::declval<T>().operator->())> > : std::true_type {};

然后有条件地启用或禁用两个版本的功能,如下所示:

template <class CopyType = Type>
typename std::enable_if<!has_arrow<CopyType>::value, CopyType *>::type
operator->() { return &object_; }  // Version 1

template <class CopyType = Type>
typename std::enable_if<has_arrow<CopyType>::value, CopyType &>::type
operator->() { return object_; }  // Version 2

【讨论】:

    猜你喜欢
    • 2014-01-30
    • 1970-01-01
    • 1970-01-01
    • 2012-04-19
    • 2012-12-04
    • 1970-01-01
    • 2013-07-16
    • 1970-01-01
    • 2023-03-31
    相关资源
    最近更新 更多