1

假设 aclass包含由嵌套定义的类型,using其析构函数需要显式调用。是否有必要用于using创建不包含命名空间分隔符(::)的本地类型?

在这个人为的例子中,我想调用A::WeakPtr's 的析构函数,比如:

wp->~A::WeakPtr();

而不是喜欢:

using AWeakPtr = A::WeakPtr;
wp->~AWeakPtr()

这是可行的吗?这是一个完整的例子。

#include <cstdlib>
#include <iostream>
#include <memory>

struct A : std::enable_shared_from_this<A> {
  using SharedPtr = std::shared_ptr<A>;
  using WeakPtr = std::weak_ptr<A>;

  A()  { std::cout << __PRETTY_FUNCTION__ << "\n"; }
  ~A() { std::cout << __PRETTY_FUNCTION__ << "\n"; }
};

int
main() {
  {
    std::unique_ptr<A::WeakPtr, void(*)(void*)>
        uwp(static_cast<A::WeakPtr*>(std::malloc(sizeof(A::WeakPtr))), std::free);
    A::WeakPtr* wp = uwp.get();

    {
      auto sp = std::make_shared<A>();
      new(wp) A::WeakPtr(sp);

      if (wp->lock())
        std::cout << "Locked\n";
      else
        std::cout << "Unlocked\n";
    }

    if (wp->lock())
      std::cerr << "EUNPOSSIBLE\n";
    else
      std::cout << "Unable to obtain lock\n";

    // Need the following 'using' statement because the following is invalid syntax:
    // wp->~A::WeakPtr();
    using AWeakPtr = A::WeakPtr;
    wp->~AWeakPtr();
    // Is there a way to call A::WeakPtr without the using statement?
  }
  std::cout << "memory held by uwp has been free(3)'ed\n";
}

似乎应该有一种方法可以通过分散在某处的::名称空间分隔符来击败typename它,但它看起来不太可能。显然,如果不可能的话,这不是世界末日,但我的古玩越来越好。


更新

正如@DanielFrey 和@DyP 的精彩回答所建议的那样,正确的语法确实是

wp->A::WeakPtr::~WeakPtr();

但这不起作用,并且是 clang++ 中的一个错误(#12350)(截至 2013 年 9 月 28 日)。

4

2 回答 2

4

你在寻找

wp->A::WeakPtr::~WeakPtr();

?

于 2013-09-27T22:36:25.523 回答
3

此处使用限定 ID的析构函数调用必须包括:

后缀表达式 -> 嵌套名称说明符 ~ 类名 ()

这里的后缀表达式wp,后面的部分->形成一个单一的 限定 ID(没有括号)。

在语法上,以下也是可能的:

后缀表达式 -> 嵌套名称说明符 ~ decltype 说明符 ()

然而,第二种形式在 [expr.prim.general]/9 中被明确禁止:

该形式~ decltype-specifier还表示析构函数,但它不应用作qualified-id中的unqualified- id 。

第一种形式的类名也可以是typedef-name [class.name]/5:

命名类类型或其cv限定版本的typedef-name (7.1.3)也是class-name

为了在之后查找这个类名~,在 [basic.lookup.qual]/5 中有一个特殊的名称查找规则:

类似地,在以下形式的限定 ID中:
     nested-name-specifier opt class-name :: ~ class-name
第二个类名在与第一个相同的范围内查找。

这意味着应该找到第二WeakPtr个。A::WeakPtr :: ~WeakPtr它是一个typedef-name命名一个类,因此是一个class-name,它在A. gcc 遵循这个规则,clang++3.4 没有。

因此,wp->A::WeakPtr :: ~WeakPtr();正如丹尼尔弗雷(以及我的第一个已删除评论/猜测)所建议的那样,应该可以工作


替代方法:

  1. 使用辅助函数:

    template<class T>
    void destroy(T& t)
    { t.~T(); }
    
  2. 使用decltype-specifier w/oaqualified -id。这个很棘手,因为 is 的类型会decltype(*wp)产生一个左值。但是,我们可以将表达式转换为纯右值以摆脱引用:A::WeakPtr&*wp

    wp->~decltype((A::WeakPtr)*wp)();
    // alternatively, w/o explicitly mentioning the type:
    wp->~decltype((std::remove_pointer<decltype(wp)>::type)*wp)();
    // simpler, using a helper function again:
    template<class T>  T helper(T const&);
    wp->~decltype(helper(*wp))();
    

生产:

从函数调用 [expr.post]/1 开始:

后缀表达式 ( 表达式列表选项 )

这里的后缀表达式是通过以下方式产生的:

后缀表达式 -> templateopt id 表达式

这里的后缀表达式映射到wp(in wp->~something())。

id 表达式包含析构函数“名称”[expr.prim.general]:

id-expression:
     unqualified-id
     合格-id

我们确实需要一个合格的ID,所以[expr.prim.general]/8:

限定 ID:
     嵌套名称说明符 templateopt unqualified-id
     :: 标识符
     :: operator-function-id
     :: literal-operator-id
     :: template-id

只有第一个是有趣的,所以我们看一下unqualified-id

unqualified-id:
     标识符
     operator-function-id
     转换-function-id
     literal-operator-id
     ~ class-name
     ~ decltype-specifier
     template-id

其中两个带a~可以用来调用析构函数。

于 2013-09-27T22:39:23.740 回答