Search code examples
c++templatesvisual-c++c++20new-operator

Ambiguous call to operator new[] when upgrading to C++ 20


I am getting an error when compiling the following code after upgrading from C++17 to C++20 with msvc:

#include <tuple>

template <typename T>
void alloc(void* dest)
{
    using ty = decltype(new T);
    reinterpret_cast<ty&>(dest) = new T;
}

int main() 
{
    int obj[5][10];
    alloc<decltype(obj)>(obj);
    return 0;
}

The error is:

<source>(7): error C2668: 'operator new[]': ambiguous call to overloaded function
predefined C++ types (compiler internal)(58): note: could be 'void *operator new[](size_t)'
predefined C++ types (compiler internal)(33): note: or       'void *operator new(size_t)'
<source>(7): note: while trying to match the argument list '(unsigned __int64)'
<source>(13): note: see reference to function template instantiation 'void alloc<int[5][10]>(void *)' being compiled

(This is a minimal repro, when I remove the tuple include then it compiles however I can't just remove the include in the real code).

Using C++ insights I can see that the c++ 17 was doing what I expected, the template substitution generated new int[5UL][10]; for new T.

I'm not sure why this is now ambiguous in C++ 20, and how I can specify what version of new I need.


Solution

  • This looks like a compiler bug.

    In your instantiation of new T the allocated type is T and is an array type. Consequently only operator new[] should be looked up for the new-expression's allocation function. This has been the case since the first C++ standard and is still the case. So void *operator new(size_t) shouldn't even be a candidate to consider in the supposedly-ambiguous overload resolution.

    However the code does have undefined behavior, see my comment under the question.