Rule A13-3-1 (required, implementation, automated)
A function that contains “forwarding reference” as its argument shall not be overloaded.
Rationale
A template parameter that is declared “T&&” (Scott Meters called it a “universal reference”, while C++ Language Standard calls it a “forwarding reference”) will deduce for any type. Overloading functions with “forwarding reference” argument may lead to developer’s confusion on which function will be called.
Exception
Declaring an overloading function that takes a “forwarding reference” parameter to be “=delete” does not violate this rule. Declaring a “forwarding constructor” that is constrained (via SFINAE) to not match any other overloads also does not violate this rule, see A14-5-1.
Example
// $Id: A13-3-1.cpp 309903 2018-03-02 12:54:18Z christof.meerwald $
#include <cstdint>
template <typename T>
void F1(T&& t) noexcept(false)
{
}
void F1(
std::int32_t&& t) noexcept // Non-compliant - overloading a function with
// forwarding reference
{
}
template <typename T>
void F2(T&& t) noexcept(false)
{
}
void F2(std::int32_t&) = delete; // Compliant by exception
class A
{
public:
// Compliant by exception, constrained to not match copy/move ctors
template<typename T,
std::enable_if_t<! std::is_same<std::remove_cv_t<std::
remove_reference_t<T>>, A>::value> * = nullptr>
A(T &&value);
};
int main(int, char**)
{
std::int32_t x = 0;
F1(x);
// Calls f1(T&&) with T = int&
F1(+x); // Calls f1(std::int32_t&&)
F1(0); // Calls f1(std::int32_t&&)
F1(0U); // Calls f1(T&&) with T = unsigned int
F2(0); // Calls f2(T&&) with T = int
// f2(x); // Compilation error, the overloading function is deleted
}
See also
HIC++ v4.0 [9]: 13.1.2 If a member of a set of callable functions includes a universal reference parameter, ensure that one appears in the same position for all other members. Effective Modern C++ [13]: Item 26. Avoid overloading on universal references.