显式调用模板参数类型的析构函数,即使在内置实例化时也是如此

Tra*_*ian 12 c++ language-lawyer

C++程序(有点出乎意料,起初对我来说)编译并运行正常,除了在结尾处注释的行main(),如果它被取消注释则是编译时错误.

#include <typeinfo>
#include <iostream>

struct Foo {
    int x;
};

template <typename T>
void create(char *buffer)
{
    std::cout << "creating " << typeid(T).name() << std::endl;
    new (buffer) T();
}

template <typename T>
void destroy(char *buffer)
{
    std::cout << "destroying " << typeid(T).name() << std::endl;
    ((T*)buffer)->~T();
}

int main(int argc, char **argv)
{
    char buffer[sizeof(Foo) > sizeof(bool) ? sizeof(Foo) : sizeof(bool)];

    // create/destroy Foo via template function calls
    create<Foo>(buffer);
    destroy<Foo>(buffer);
    // now do the above explicitly...
    new (buffer) Foo();
    ((Foo*)buffer)->~Foo();

    // create/destroy bool via template function calls
    create<bool>(buffer);
    destroy<bool>(buffer);
    // now do the above explicitly...
    new (buffer) bool();
    // ((bool*)buffer)->~bool(); // oops, doesn't work

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我从中得知C++(或者至少是g ++的C++思想)允许对模板参数类型进行"显式析构函数调用",即使手动执行类型替换也会导致语法错误(因为bool实际上并没有真正的析构函数来调用).

为了更明确,行:

((T*)buffer)->~T();
Run Code Online (Sandbox Code Playgroud)

当T在a上实例化时编译并运行正常bool,但对实际执行相同的操作bool:

((bool*)buffer)->~bool();
Run Code Online (Sandbox Code Playgroud)

是语法错误.

我发现这种行为,因为我正在进行模板元编程并发现它非常有用,所以我猜它是标准的,并且专门用于处理像我上面那样的案例.有没有人确切知道这是否真的如此,并且当这种行为被标准化时,如果是这样的话?

此外,任何人都可以指出标准中的确切措辞是什么,以及它允许​​的情况范围?(我不擅长阅读标准,所以我很难自己解决这个问题.)

T.C*_*.C. 11

这确实是有效的C++(据我所知,从C++ 98开始),被称为伪析构函数调用.N4431§5.2.4[expr.pseudo]:

1 在点或箭头 运算符后使用伪析构函数名称表示由type-namedecltype-specifier表示的非类型类型的析构函数 .结果只能用作函数调用运算符的操作数,并且这种调用的结果具有类型.唯一的效果是在点或箭头之前评估 后缀表达式..->()void

2点运算符的左侧应为标量类型.箭头操作符的左侧应是指向标量类型的指针.此标量类型是对象类型.对象类型的cv非限定版本和伪析构函数名称指定的类型 应为相同类型.此外,表单的伪析构函数名称中的两个类型名称

nested-name-specifier_opt type-name :: ~ type-name
Run Code Online (Sandbox Code Playgroud)

应指定相同的标量类型.

伪析构函数名是(第5.2节[expr.post])之一:

nested-name-specifier_opt type-name :: ~ type-name
nested-name-specifier template simple-template-id :: ~ type-name
~ type-name
~ decltype-specifier
Run Code Online (Sandbox Code Playgroud)

虽然类型名称是中的一个(§7.1.6.2[dcl.type.simple])

class-name
enum-name
typedef-name
simple-template-id
Run Code Online (Sandbox Code Playgroud)

bool不是类型名称,因此~bool()版本是语法错误.在模板内部,模板类型参数是typedef-name(§14.1[temp.param]/p3),它是一个类型名称,因此~T()版本编译.

  • @martin(假设你的意思是标量类型)我的猜测是故意的; 没有必要让人们编写完全无用的代码. (3认同)