4

Consider this code (godbolt):

#include <type_traits>
#include <memory>
#include <cstdlib>

using namespace std;

template<auto L, class T = decltype(L)>
using constant = integral_constant<T, L>;

int main() 
{
    unique_ptr<void, constant<&free>> p1;
    unique_ptr<void, constant<free>> p2;    // <-- MSVC refuses to compile this line
    return 0;
}

Why does MSVC refuse to compile the highlighted line? Is this code valid?

MSVC produces:

<source>(13): error C2975: 'L': invalid template argument for 'constant', expected compile-time constant expression
<source>(7): note: see declaration of 'L'
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
C.M.
  • 3,071
  • 1
  • 14
  • 33
  • 3
    It just says "I refuse"? – jarmod Feb 04 '22 at 22:00
  • @jarmod My bad. Fixed... – C.M. Feb 04 '22 at 22:03
  • 3
    `::free` and `std::free` compile, so `free` might be being replaced by some compiler intrinsic – Artyer Feb 04 '22 at 22:09
  • 3
    Removing `using namespace std;` and qualifying `unique_ptr` with `std::` accordingly also makes the program compile. `free` may simply alias the C lib version which has C language linkage, but that shouldn't matter for an `auto` non-type template parameter (but does for when trying to assign to function pointer with C++ language linkage a function address with language linkage, maybe this plays into the apparent buggy behaviour here). – dfrib Feb 04 '22 at 22:32
  • [Why is "using namespace std;" considered bad practice?](https://stackoverflow.com/q/1452721/995714) – phuclv Feb 05 '22 at 09:02

1 Answers1

3

Pre-C++20 it looks like a MSVC bug.

After C++20, the behavior is unspecified (thanks @heapunderrun) since free is not in the list of functions you're allowed to take the addresses of. But I'd argue that it's still a bug (even if conformant), since MSVC lets you take the address of the same function if you use &.


Template argument deduction in this case is done as if by constexpr auto x = free; ([temp.arg.nontype]/1), and the above declaration is accepted by MSVC, deducing a function pointer.

Some implicit conversions are banned when passing a template argument, the allowed conversions are listed in [expr.const]/10 and include a "function-to-pointer conversion".

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
  • Any idea why `::free` works for MSVC and `free` -- doesn't? – C.M. Feb 04 '22 at 22:21
  • 1
    @C.M. Possibly this https://stackoverflow.com/questions/55687044/can-i-take-the-address-of-a-function-defined-in-standard-library as `free` is `std::free` because of `using namespace std;` – Richard Critten Feb 04 '22 at 22:33
  • 5
    But is such function-to-pointer conversion still guaranteed to succeed here, taking into account that `std::free` is **not** among the designated [addressable functions](https://en.cppreference.com/w/cpp/language/extending_std#Addressing_restriction)? – heap underrun Feb 04 '22 at 22:56
  • So, in C++20 they made it harder to make those auto-release objects (that require `free` or whatever) again... sigh... – C.M. Feb 07 '22 at 02:41