假设class
包含由嵌套using
定义的类型,其需要显式调用析构函数。是否有必要使用using
创建不包含命名空间分隔符(::
)的本地类型?
在这个人为的例子中,我想调用A::WeakPtr
的析构函数,如:
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的fantastic answer的建议,正确的语法确实是
wp->A::WeakPtr::~WeakPtr();
但这不起作用,并且是clang ++中的错误(#12350)(截至2013-09-28)。
答案 0 :(得分:4)
您在寻找
吗?wp->A::WeakPtr::~WeakPtr();
答案 1 :(得分:3)
此处使用 qualified-id 的析构函数调用必须包含:
postfix-expression ->
nested-name-specifier ~
class-name ()
postfix-expression 此处为wp
,->
之后的部分形成单 qualified-id (没有parens)。
在语法上,以下也是可能的:
postfix-expression ->
nested-name-specifier ~
decltype-specifier ()
但是,在[expr.prim.general] / 9中明确禁止使用第二种形式:
表单
~ decltype-specifier
也表示析构函数,但它不能用作 qualified-id 中的 unqualified-id 。
第一种形式的 class-name 也可以是 typedef-name [class.name] / 5:
命名类类型的 typedef-name (7.1.3)或 cv - 限定版本,也是类名< / em>的
要在~
之后查找此类名,[basic.lookup.qual] / 5中有一个特殊的名称查找规则:
同样,在形式的 qualified-id 中:
nested-name-specifier opt class-name:: ~
class-name
第二个类名在与第一个相同的范围内查找。
这意味着应找到WeakPtr
中的第二个A::WeakPtr :: ~WeakPtr
。它是一个 typedef-name 命名一个类,因此是一个类名,它在A
的范围内查找。 gcc遵循这个规则,clang ++ 3.4没有。
因此wp->A::WeakPtr :: ~WeakPtr();
suggested Daniel Frey {{3}}(我的第一个,删除的评论/猜测)应该有用。
替代方法:
使用辅助函数:
template<class T>
void destroy(T& t)
{ t.~T(); }
使用 decltype-specifier 没有 qualified-id 。这个很棘手,因为decltype(*wp)
的类型是A::WeakPtr&
,因为*wp
会产生左值。但是,我们可以将表达式转换为prvalue以摆脱引用:
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开始:
postfix-expression
(
表达式列表 opt)
这里的 postfix-expression 是通过以下方式生成的:
postfix-expression
-> template
opt id-expression
此后缀表达式此处映射到wp
(wp->~something()
)。
id-expression包含析构函数“name”[expr.prim.general]:
ID-表达:
不合格-ID
合格-ID
我们在这里需要 qualified-id ,所以[expr.prim.general] / 8:
合格-ID:
嵌套名称说明符template
opt unqualified-id
::
标识符
::
operator-function-id
::
literal-operator-id
::
template-id
只有第一个是有意义的,所以我们看一下 unqualified-id :
不合格-ID:
标识符
操作员功能-ID
转换函数-ID
字面运营商-ID
~
类名
~
decltype-specifier
模板id
可以使用~
的两个来调用析构函数。