【问题标题】:unique_ptr deleter trick: which compiler is correct?unique_ptr 删除技巧:哪个编译器是正确的?
【发布时间】:2021-11-30 02:44:10
【问题描述】:

我正在通过this particular SO 了解如何为自定义删除器指针节省内存空间。在答案的底部,它提供了 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 作为其实例化)。

那么问题来了:哪个编译器是正确的?

【问题讨论】:

标签: c++ templates c++17 language-lawyer constexpr


【解决方案1】:

这似乎是一个 gcc 错误,和一个完全不同的 MSVC 错误。

gcc 不能这样做:

template <typename T, T t> struct foo {};

当用函数类型实例化时。 T 必须是触发此错误的模板参数; template &lt;void t(void*) noexcept&gt; 有效。

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 不能用作模板参数。

【讨论】:

  • 不确定从哪个 C++ 版本开始,但所有 STL 函数都将作为可调用对象进行处理 - 因此不能合法地将它们转换为函数指针。
  • @ALX23z:它也适用于C函数吗?
  • val&lt;decltype(&amp;free), &amp;free&gt; 似乎是一个更好的解决方案。
猜你喜欢
  • 2020-04-13
  • 1970-01-01
  • 2014-12-31
  • 2011-06-15
  • 2016-03-30
  • 2016-09-15
  • 2018-03-30
  • 2018-03-27
  • 1970-01-01
相关资源
最近更新 更多