unique_ptr删除人的把戏:编译器是正确的?



我正在讨论如何为自定义删除指针节省内存空间。在答案的底部,它提供了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库函数。)一个简单的解决方案是使用限定名(::freestd::free,两者都可以)。将free封装在另一个函数中也可以解决这个问题。这是因为MSVC显然认为(在这种情况下)::freestd::free是不同的函数,无法消除歧义。没有标准库也可以复制:

void foo(void*);
namespace moo {
using ::foo;
}
using namespace moo;

现在普通的foo不能用作模板参数

相关内容

  • 没有找到相关文章

最新更新