Search code examples
c++templatesc++20

Error of universal Reference on Function Template


I am trying to write a function template that takes a universal reference as parameter so it can accept both lvalue reference and rvalue reference.

When I write this:

template <typename Type>
concept is_number = std::integral<Type> || std::floating_point<Type>;

template <typename Type1, typename Type2>
    requires is_number<Type1> && is_number<Type2>
[[nodiscard]] inline auto add(Type1&& num1, Type2&& num2) noexcept
{
    return num1 + num2;
}

const std::int64_t num1 { 50 };
const double num2 { 30.6 };

std::cout << add(num1, num2) << std::endl;

The code works as expected. The add() function template successfully deduced as

[[nodiscard]] inline double add(const std::int64_t& num1, const double& num2);

However, when I try this code:

template <typename Type>
    requires is_number<Type>
[[nodiscard]] inline auto absolute(Type&& number) noexcept
{
    return number < 0 ? -(number) : number;
}

const double num3 { -12.5 };

std::cout << absolute(num3) << std::endl;   // Compiler warns: no matching overloaded function found

Am I missing something here?


Solution

  • Universal references will make templates deduce reference types. This means that Type will probably be std::int64_t&. This is required for forwarding references to work.

    Now your check is checking if the type is an integral or floating point. The type it receives is std::int64_t& or float const&, and both types are not numbers. They are references

    To make it work you need to remove qualifiers when using your concept:

    template <typename Type>
        requires is_number<std::remove_cvref_t<Type>>
    [[nodiscard]] inline auto absolute(Type&& number) noexcept
    {
        return number < 0 ? -(number) : number;
    }