假设一个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 << "Lockedn";
else
std::cout << "Unlockedn";
}
if (wp->lock())
std::cerr << "EUNPOSSIBLEn";
else
std::cout << "Unable to obtain lockn";
// 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)'edn";
}
似乎应该有一种方法来击败::
名称空间分隔符,在其中的某个地方散布一个typename
,但看起来这是不可能的。显然,如果不可能的话,这不是世界末日,但我的古玩正在战胜我。
更新
正如@DanielFrey和@DyP的精彩回答所建议的那样,正确的语法确实是
wp->A::WeakPtr::~WeakPtr();
但这不起作用,并且是clang++中的一个bug(#12350)(截至2013-09-28)。
你在找吗
wp->A::WeakPtr::~WeakPtr();
此处使用限定id的析构函数调用必须包含:
后缀表达式->
嵌套名称说明符~
类名()
这里的后缀表达式是wp
,->
之后的部分形成单个限定id(没有parens)。
从语法上讲,以下也是可能的:
后缀表达式->
嵌套名称说明符~
decltype说明符()
然而,第二种形式在[expr.prim.general]/9:中被明确禁止
形式
~ decltype-specifier
也表示析构函数,但它不应用作限定id中的非限定id。
第一种形式中的类名也可以是typedef名称[class.name]/5:
命名类类型的typedef-name(7.1.3),或其cv限定版本,也是类名。
对于在~
之后查找此类名,在[basic.lookup.qual]/5:中有一个特殊的名称查找规则
类似地,在形式的合格id中:
nbsp nbsp嵌套名称说明符opt类名:: ~
类名称与第一个相同的范围中查找第二个类别名称。
这意味着应该找到A::WeakPtr :: ~WeakPtr
中的第二个WeakPtr
。它是一个命名类的typedef名称,因此是一个类名。它在A
的范围中查找。gcc遵循这个规则,clang++3.4没有。
因此,Daniel Frey建议的wp->A::WeakPtr :: ~WeakPtr();
(以及我的第一个已删除的评论/猜测)应该有效。
替代方法:
-
使用辅助函数:
template<class T> void destroy(T& t) { t.~T(); }
-
使用decltype说明符w/o限定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:开始
后缀表达式
(
表达式列表opt)
此处的后缀表达式通过:生成
后缀表达式
-> template
optid表达式
此后缀表达式此处映射到wp
(在wp->~something()
中)。
id表达式包含析构函数"name"[expr.prim.general]:
id表达式:
nbsp nbsp不合格id
nbsp 合格id
我们确实需要一个合格的id,所以[expr.prim.general]/8:
合格id:
nbsp nbsp 嵌套名称说明符template
nbsp::
标识符
nbsp nbsp::
运算符函数id
nbsp nbsp::
文字运算符id
nbsp nbsp::
模板id
只有第一个感兴趣,所以我们看不合格的ids:
不合格id:
nbsp nbsp 标识符
nbsp 运算符函数id
nbsp nbsp 转换函数id
nbsp nbsp 文字运算符id
nbsp nbsp~
类名
nbsp nbsp~
decltype说明符
nbsp nbsp 模板id
其中具有~
的两个可以用于调用析构函数。