Zamfir Yonchev
Zamfir Yonchev

Reputation: 161

const and non-const parameter function overloads with a single definition

I have the following 2 function overloads:

template<typename F, typename T>
void func(F f, std::vector<T>& v) { ... }

template<typename F, typename T>
void func(F f, const std::vector<T>& v) { ... }

The body of both of them is the same. Is there an easy way to define them both with a single definition to avoid code duplication using C++17 or earlier standard?

Just to clarify, I want the functions to be constrained based on the std::vector part but I want to allow const and non-const references to be passed. The reason I need both overloads is that the F function object will be applied to the vector and sometimes F will modify the vector and sometimes it will only observe the vector (and I want to allow the vector to be declared const in the second case).

I guess I can use C++20 concepts to constrain the function template parameter but I was wondering if there's an easy way to achieve the same thing using C++17 or earlier version of the standard.

Upvotes: 0

Views: 120

Answers (2)

Zamfir Yonchev
Zamfir Yonchev

Reputation: 161

I found another solution but it still adds a little bit of overhead:

template<typename F, typename VecT>
auto func_vec(F f, VecT& vec)
{
  //actual code
}

template<typename F, typename T>
auto func(F f, std::vector<T>& vec) { return func_vec(f, vec); }

template<typename F, typename T>
auto func(F f, const std::vector<T>& vec) { return func_vec(f, vec); }

A third function is defined (func_vec) which holds the actual implementation of func.

Note that typename VecT can accept both const and non-const arguments.

func overloads are just used to constrain the argument to be of type std::vector<T>& with or without a const qualifier.

The good thing about this solution is that it doesn't use SFINAE and is fairly easy to read. The bad thing is that you have to introduce another function template for the actual implementation.

Upvotes: 0

apple apple
apple apple

Reputation: 10591

you don't need require clause to do sfinae,

#include <vector>
#include <type_traits>

template<typename T>
struct is_vector : std::false_type{};
template<typename ...Args>
struct is_vector<std::vector<Args...>> : std::true_type{};

template<
    typename F,
    typename C,
    std::enable_if_t<is_vector<std::remove_cvref_t<C>>::value,std::nullptr_t> = nullptr
>
void func(F f, C&& v) {
   // ...
}

* std::remove_cvref_t is still c++20, you need to use std::remove_cv_t<std::remove_reference_t<T>> in earlier standard

Upvotes: 1

Related Questions