unique_ptr 删除技巧:哪个编译器是正确的?
unique_ptr deleter trick: which compiler is correct?
我正在研究 this particular SO 如何为自定义删除器指针节省内存 space。在答案的底部,它提供了C++11中的自定义编写版本。
在尝试理解代码几十分钟后,我发现 Big 3 之间存在一些编译器不一致的地方,其中 clang 编译,而其他两个则抱怨编译器错误。 (Live Demo)
我的代码与其他 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;
现在 plain foo
不能用作模板参数。
我正在研究 this particular SO 如何为自定义删除器指针节省内存 space。在答案的底部,它提供了C++11中的自定义编写版本。
在尝试理解代码几十分钟后,我发现 Big 3 之间存在一些编译器不一致的地方,其中 clang 编译,而其他两个则抱怨编译器错误。 (Live Demo)
我的代码与其他 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;
现在 plain foo
不能用作模板参数。