Home > front end >  C less verbose way to input template argument
C less verbose way to input template argument

Time:04-10

I'm practicing Algorithms textbook and modern C coding. I wrote a brief test that verifies sorting functions as the following: (I know using namespace std; is discouraged in production, so please don't advice on that)

namespace frozenca {

using namespace std;

template <ranges::input_range R>
void print(R&& r, ostream& os = cout) {
    for (auto elem : r) {
        os << elem << ' ';
    }
    os << '\n';
}

mt19937 gen(random_device{}());

template <typename F, ranges::forward_range R = vector<int>> requires regular_invocable<F, R>
void verify_sorting(F&& f, int num_trials = 1'000, int max_length = 1'000) {
    uniform_int_distribution<> len_dist(0, max_length);

    for (int i = 0; i < num_trials;   i) {
        R v;
        int n = len_dist(gen);
        generate_n(back_inserter(v), n, ref(gen));
        f(v);
        if (!ranges::is_sorted(v)) {
            throw runtime_error("Sorting verification failed");
        }
    }
    std::cout << "Sorting verification success!\n";

}

} // namespace frozenca

and I wrote an insertion sort code like this:

namespace frozenca {

using namespace std;

struct insertion_sort_func {
    template <ranges::bidirectional_range R = vector<int>, typename F = ranges::greater>
    constexpr void operator()(R&& r, F comp = {}) const {
        if (ranges::empty(r)) return;
        for (auto i = next(begin(r)); i != end(r);   i) {
            auto key = *i;
            auto j = i;
            while (j != begin(r) && comp(*prev(j), key)) {
                iter_swap(prev(j), j);
                --j;
            }
            *j = key;
        }
    }
};

inline constexpr insertion_sort_func insertion_sort{};

} // namespace frozenca

And here is my test code, which works nicely:


int main() {
    namespace fc = frozenca;

    std::vector<int> v{5, 2, 4, 6, 1, 3};
    fc::insertion_sort(v);
    fc::print(v); // outputs "1 2 3 4 5 6"
    fc::verify_sorting(std::ranges::sort); // outputs "Sorting verification success!"
    fc::verify_sorting(fc::insertion_sort); // outputs "Sorting verification success!"

}

My verify_sorting function tests the sorting function for type std::vector<int> by default. Of course it can test other std::ranges::forward_range, but it becomes extremely verbose. For testing std::vector<float>, what I checked working is like this:

fc::verify_sorting<decltype(fc::insertion_sort), std::vector<float>>
(std::forward<decltype(fc::insertion_sort)>(fc::insertion_sort));
// OK

This is way too verbose. Is there any less verbose way?

Running code: https://wandbox.org/permlink/4UPLxeJxDlOkXcN1

CodePudding user response:

This is way too verbose. Is there any less verbose way?

Just change the order of template parameters

template <ranges::forward_range R = vector<int>, typename F> 
  requires regular_invocable<F, R>
void verify_sorting(F&& f,  /* */);

Then you can just invoke like this

fc::verify_sorting(std::ranges::sort);
fc::verify_sorting(fc::insertion_sort);
fc::verify_sorting<std::vector<float>>(fc::insertion_sort);

Demo

  • Related