我正在讨论如何为自定义删除指针节省内存空间。在答案的底部,它提供了c++ 11的自定义编写版本。
在花了几十分钟试图理解代码之后,我发现Big 3中的一些编译器不一致,其中clang可以编译,而其他两个则抱怨编译器错误。(现场演示)我的代码与其他SO答案略有不同。是这样的:
#include <cstdlib>
#include <iostream>
#include <memory>
#include <type_traits>
using namespace std;
template <class T, T t>
struct val {
constexpr operator typename decay<T>::type() const noexcept {
return t;
}
};
using default_free = val<decltype(free), free>;
int main(void) {
unique_ptr<void, default_free> p(malloc(42));
cout << p.get() << endl;
p.reset();
cout << p.get() << endl;
return 0;
}
如果我错了,请纠正我。在我看来,诀窍是提供一个constexpr函数,它可以将类型为default_delete
的对象转换为值为t
的函数指针(free
作为其实例化)。
那么问题来了:哪个编译器是正确的?
这似乎是一个gcc错误,并且是一个完全不同的MSVC错误。
gcc不能这样做:
template <typename T, T t> struct foo {};
当用函数类型实例化时。T
必须是触发此错误的模板参数;template <void t(void*) noexcept>
作品。
template <typename T, T* t> struct foo {};
修复问题。
MSVC很好地使用了前面的两种结构,但是它不能使用free
作为非类型模板参数。(还有其他标准C库函数。)一个简单的解决方案是使用限定名(::free
或std::free
,两者都可以)。将free
封装在另一个函数中也可以解决这个问题。这是因为MSVC显然认为(在这种情况下)::free
和std::free
是不同的函数,无法消除歧义。没有标准库也可以复制:
void foo(void*);
namespace moo {
using ::foo;
}
using namespace moo;
现在普通的foo
不能用作模板参数