Yichao Zhou
Yichao Zhou

Reputation: 465

Is it possible to write one template function that accepts both rvalue and lvalue

I want to add the arithmetic overload for std::vector (probably not a very good idea but I want to use this as an example). I can implement it as the following

template <typename T, typename T2> auto& operator+=(std::vector<T>& a, const std::vector<T2>& b)
{
    assert(a.size() == b.size());

    std::transform(a.begin(), a.end(), b.begin(), a.begin(), std::plus<>());
    return a;
}

template <typename T, typename T2> auto operator+(const std::vector<T>& a, 
const std::vector<T2>& b)
{
    auto a0 = a;
    return a0 += b;
}

template <typename T, typename T2> auto operator+(std::vector<T>&& a, 
const std::vector<T2>& b)
{
    auto a0 = a;
    return a0 += b;
}

I need to write two function for operator+ in order to exploit the rvalue sementic in C++11. Is it possible to remove the duplicated code for operator+?

Upvotes: 0

Views: 80

Answers (2)

Massimiliano Janes
Massimiliano Janes

Reputation: 5624

you can use perfect-forwarding and possibly constrain via SFINAE, something like

template<typename T>
struct is_vector_addable: std::false_type {};

template<typename T>
struct is_vector_addable<std::vector<T>>: std::true_type {};

template <typename T, typename T2,typename E=
std::enable_if_t< is_vector_addable<std::decay_t<T>>::value >>
auto operator+( T&& a,  const std::vector<T2>& b)
{
    auto a0 = std::forward<T>(a);
    return a0 += b;
}

as suggested by Sebastian Redl, you may also further constrain to std::vector's having addable elements ( in the sense of std::transform with std::plus semantics, this may or may not be what you really want ), in C++17:

template<typename T,typename T2,typename = void>
struct is_vector_addable: std::false_type {};

template<typename T,typename T2>
struct is_vector_addable<std::vector<T>,T2,std::void_t<
  decltype( std::declval<T>() = std::declval<T>() + std::declval<T2>() )
  >>: std::true_type {};

template <typename T, typename T2,typename E=std::enable_if_t< is_vector_addable<std::decay_t<T>,T2>::value >>
auto operator+( T&& a,  const std::vector<T2>& b)

Upvotes: 4

Jarod42
Jarod42

Reputation: 217225

Whereas perfect forwarding is a solution in general case, an alternative is to pass by value:

template <typename T, typename T2>
auto operator+(std::vector<T> lhs, const std::vector<T2>& rhs)
{
    return lhs += rhs;
}

Upvotes: 4

Related Questions