I was going through this particular SO on how to save memory space for custom deleter pointer. At the bottom of the answer, it provides a custom written version in C 11.
After dozens of minutes trying to understand the code, I discover some compiler inconsistencies among the Big 3, where clang compiles, while the other two complain with compiler errors. (Live Demo)
My code is a little different from the other SO answer. Here it goes:
#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;
}
Please correct me if I'm wrong here. The way I see it, the trick is to provide a constexpr function that can cast an object of type default_delete
to a function pointer with the value of t
(free
as its instantiation).
So the question: which compiler is correct?
CodePudding user response:
It appears to be a gcc bug, and a completely different MSVC bug.
gcc cannot do this:
template <typename T, T t> struct foo {};
when instantiated with a function type. T
has to be a template parameter for this bug to be triggered; template <void t(void*) noexcept>
works.
template <typename T, T* t> struct foo {};
fixes the problem.
MSVC eats either of the previous constructs perfectly well, but it cannot use free
as a non-type template argument. (Other standard C library functions as well.) A simple solution is to use a qualified name (either ::free
or std::free
, both work). Wrapping free
in another function also fixes the problem. This is because MSVC apparently thinks (in this context) that ::free
and std::free
are different functions, and cannot disambiguate. One can reproduce this with no standard library:
void foo(void*);
namespace moo {
using ::foo;
}
using namespace moo;
Now plain foo
cannot be used as a template parameter.