不相关的专业化必须存在才能编译?
下面的代码(可以正确编译和执行,做我想要的事情)是我在编写一个类来存储各种类型的属性时遇到的一个奇怪的最小示例,这些类型需要在不再知道其类型时删除指针的能力。我的解决方案是使用模板化函数创建一个删除器类,该函数可以获取并存储其地址以删除特定类型。 我不明白为什么这段代码有效,特别是:
- 为什么它没有命中断言?
- 为什么/如何需要/使用(看似)不相关的专业化?
代码:
#include <iostream>
#include <string>
#include <cassert>
#include <locale> //Just here as an unused class to specialize
using namespace std;
typedef void(*void_voidptr_func_t)(void*);
class ClassWithDestructor {
public:
~ClassWithDestructor() {
cout << "Destroyed\n";
}
};
class Deleter {
public:
template <class T>
static void Delete (T* ptr) {
assert(0);
}
//locale here can be any class
//it doesn't matter what class it is
//but if this specialization doesn't exist
//compile fails
template <class locale>
static void Delete(void* ptr) {
delete (locale*)ptr;
}
};
void* void_ptr_to_T = NULL;
void_voidptr_func_t T_delete_function = NULL;
template<class T>
void A() {
T* t = new T;
void_ptr_to_T = (void*)t;
T_delete_function = &Deleter::Delete<T>;
}
int main(int argc, char** argv) {
A<ClassWithDestructor>();
T_delete_function(void_ptr_to_T);
}
编译器:MSVC++ 2010,禁用 Microsoft 扩展
输出:
被摧毁
The following code (which compiles and executes properly, doing what I want) is a minimal example of an oddity I experienced while writing a class to store properties of various types that needed the ability to delete pointers when it no longer knows their types. My solution was to make a Deleter class with a templated function that could have its address taken and stored to delete a specific type. I don't understand why this code works, specifically:
- Why doesn't it hit the assert?
- Why/how does it require/use the (seemingly) unrelated specialization?
Code:
#include <iostream>
#include <string>
#include <cassert>
#include <locale> //Just here as an unused class to specialize
using namespace std;
typedef void(*void_voidptr_func_t)(void*);
class ClassWithDestructor {
public:
~ClassWithDestructor() {
cout << "Destroyed\n";
}
};
class Deleter {
public:
template <class T>
static void Delete (T* ptr) {
assert(0);
}
//locale here can be any class
//it doesn't matter what class it is
//but if this specialization doesn't exist
//compile fails
template <class locale>
static void Delete(void* ptr) {
delete (locale*)ptr;
}
};
void* void_ptr_to_T = NULL;
void_voidptr_func_t T_delete_function = NULL;
template<class T>
void A() {
T* t = new T;
void_ptr_to_T = (void*)t;
T_delete_function = &Deleter::Delete<T>;
}
int main(int argc, char** argv) {
A<ClassWithDestructor>();
T_delete_function(void_ptr_to_T);
}
Compiler: MSVC++ 2010, Microsoft Extensions Disabled
Output:
Destroyed
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这
不是一个专业。这是一个超载。专业化是这样的
所以实际上它相当于编写
实际上,您呈现的行为是因为线路上的重载解析
第二个重载更具体,因为它接受
void*
而不是T*
无论如何,类型都是明确指定的。因此,在存在上述重载的情况下,它会选择它,并且可以很好地编译和运行。如果没有这种更具体的重载,编译器将调用另一个适当的但更通用的重载来触发断言。您可以仔细检查,即删除
#include
行:编译器不会抱怨class locale
未声明。This
is not a specialization. This is an overload. A specialization would be like this
So actually it's equivalent to writing just
Actually, the behavior you presented is because of the overload resolution on the line
The second overload is more specific as it accepts
void*
and notT*
and type is specified explicitly anyway. So in presence of the mentioned overload it chooses it and it compiles and runs finely. In absence of this more specific overload, compiler calls another appropriate, but more general one which fires the assertion.You can double check that, i.e. remove the
#include <locale>
line: compiler will not complain aboutclass locale
being undeclared.这里没有专门化:您有两个(不同的)重载函数模板:
&Deleter::Delete
可以引用任一Delete
函数模板。在您的示例中选择 (2) 是因为它的类型与您要分配的函数指针的类型匹配。函数指针的类型为void(*)(void*)
; (1) 转换为函数指针的类型为void(*)(T*)
,除非T = void
,否则它会匹配。There are no specializations here: you have two (different) function templates that overload:
&Deleter::Delete<T>
could refer to either of theDelete
function templates. (2) is selected in your example because its type matches the type of the function pointer to which you are assigning. The type of the function pointer isvoid(*)(void*)
; the type of (1) converted to a function pointer isvoid(*)(T*)
, which does match unlessT = void
.