Search code examples
c++templatesimplicit-conversion

Why did newer compilers start accepting this template function call?


The following small C++ program involving a call to the template function std::atomic_fetch_add() fails to compile in godbolt for x86-64 clang versions less than 9.0 and gcc versions less than 9.1, in both cases using the --std=c++11 option.

#include <iostream>
#include <atomic>

std::atomic<char> ch ('@');

int main ()
{
    std::atomic_fetch_add (&ch, 5);
    std::cout << ch << std::endl;
}

In those early compiler versions (it might be more related to the C++ libraries provided by the compilers, I'm not sure), the std::atomic_fetch_add (&ch, 5); call fails to match any template specialization for the atomic fetch function, since the type of ch is char, and the type of 5 is int:

: In function 'int main()': :8:34: error: no matching function for call to 'atomic_fetch_add(std::atomic*, int)' std::atomic_fetch_add (&ch, 5); ...

However, later versions of the compiler (& libraries?) successfully compile this usage.

  1. What changed to make this start compiling?
  2. If it is a standard library change, what technique is used to allow this?
  3. Does the C++ standard (& what version?) require that this usage should work.

I'm pretty much a C++ beginner, but I gather that this is related to implicit conversions not being performed as part of figuring out the appropriate template specialization to use. (I may not be using precise language.)

I know that I can modify the call to work by rewriting it as either

std::atomic_fetch_add<char> (&ch, 5);

or

std::atomic_fetch_add (&ch, (char)5);

However, I'm interested in getting a version of the <atomic> library to support the usage without the explicit instantiation and without the cast. (The compiler is clang 15.0.0, --std=c++11. The library is a proprietary version of the Dinkum libraries.)

I need to understand how to support the calling of template functions like std::atomic_fetch_char (&ch, 5) where the argument types do not exactly match those in the template declaration. I would, for example, like to understand how this is supported in the linux /usr/include/c++/11/ standard library.

The nearest I've come up with myself is to add non-template overloads of various instantiations of std::atomic_fetch_add() & similar functions, but I don't see that being done in the Linux/GNU C++ libraries and I suspect there is a cleaner way. I want to understand it.


Solution

  • Originally std::atomic_fetch_add required the second parameter to have the same type as the value_type of the atomic object as both parameters participated in type deduction.

    This was removed with defect report P0558R1 so that deduction only happens on the atomic object and the second parameter is just converted to the differece_type of the atomic object.

    You get the error because older versions didn't get patched with this defect report but newer versions did.