2

I can't understand how can I use lambda with generic arguments and pass it as parameter in another method.
Below my code that I have now (wrong, of course):

class Arrays final
{
public:    
    template<class RandomIt>
    static void InsertionSort(RandomIt first, RandomIt last) {
        auto func = [](RandomIt lt, RandomIt rt) {
            return *lt > (*rt);
        };
        InsertSort(first, last, func);
    }

    template<class RandomIt>
    static void InsertionSortDesc(RandomIt first, RandomIt last) {
        auto func = [](RandomIt lt, RandomIt rt) {
            return *lt < (*rt);
        };
        InsertSort(first, last, func);
    }

private:
    Arrays();

    template<class RandomIt>
    static void InsertSort(RandomIt first, RandomIt last,
                         std::function<bool (RandomIt, RandomIt)> func) {
        int length = std::distance(first, last);

        if (length < 2) {
            return;
        }

        RandomIt j = first + 1;

        for (; j != last; ++j) {
            auto key = *j;
            RandomIt i = j - 1;

            while (i >= first && func(i, j)) {
                *(i + 1) = (*i);
                --i;
            }

            *(++i) = key;
        }
    }
};

It crashes in the compile time with errors:

arrays.h:38: error: no matching function for call to 'Arrays::InsertSort(const int*&, const int*&, Arrays::InsertionSort(RandomIt, RandomIt) [with RandomIt = const int*]::<lambda(const int*, const int*)>&)'
         InsertSort(first, last, func);
                   ^

How to write it correctly? Is it possible in C++ v11?

6
  • 1
    To be honest, I would change InsertSort to be template <class RandomIt, class Compare> static void InsertSort(RandomIt first, RandomIt last, Compare && func) { .... There is no reason to require the argument to be an std::function instance; any suitable callable should do. Commented Apr 18, 2017 at 1:44
  • @cdhowie, sorry, Imma noobie in C++. But I don't see in this declaration any check of argument types of function i.e I can pass a wrong function (with other arguments)? Will it crash in the compile time in this case? Commented Apr 18, 2017 at 1:48
  • Yes, if you pass a callable where the arguments can't be converted, the template will fail to instantiate. Commented Apr 18, 2017 at 1:54
  • @cdhowie, I tried your solution and got a new error: arrays.h:67: ошибка: assignment of read-only location '*(i + 4u)' *(i + 1) = (*i); ^ Commented Apr 18, 2017 at 1:54
  • 1
    Well, based on the compiler error in your question, you are passing in a const int * (pointer to constant int), so what did you expect? Show the code where you call Arrays::InsertionSort(). Commented Apr 18, 2017 at 1:56

1 Answer 1

2

Note: I have NOT tested your code. However, the following compiles. The function is static therefore its declaration must come in ORDER of usage. To fix it, move the declaration of InsertSort before all other functions that use it. Next, you need to call InsertSort with the template parameter.

Ex:

#include <iostream>
#include <vector>

class Arrays final
{
private:
    Arrays();

    template<class RandomIt>
    static void InsertSort(RandomIt first, RandomIt last,
                           std::function<bool (RandomIt, RandomIt)> func) {
        auto length = std::distance(first, last);

        if (length < 2) {
            return;
        }

        RandomIt j = first + 1;


        for (; j != last; ++j) {
            auto key = *j;
            RandomIt i = j - 1;

            while (i >= first && func(i, j)) {
                *(i + 1) = (*i);
                --i;
            }

            *(++i) = key;
        }
    }

public:
    template<class RandomIt>
    static void InsertionSort(RandomIt first, RandomIt last) {
        auto func = [](RandomIt lt, RandomIt rt) {
            return *lt > (*rt);
        };
        InsertSort<RandomIt>(first, last, func);
    }

    template<class RandomIt>
    static void InsertionSortDesc(RandomIt first, RandomIt last) {
        auto func = [](RandomIt lt, RandomIt rt) {
            return *lt < (*rt);
        };
        InsertSort<RandomIt>(first, last, func);
    }
};

int main(int argc, const char * argv[]) {

    std::vector<int> vec = {1, 9, 4, 5, 2, 3, 8, 6, 7};

    Arrays::InsertionSort(vec.begin(), vec.end());


    for (auto i : vec) {
        std::cout<<i<<" ";
    }

    std::cout<<std::endl;

    return 0;
}

As noted in a comment :D You don't have to change the declaration order if you qualify the call to the function..

Ex: Arrays::InsertSort<RandomIt>(....);

class Arrays final
{
public:
    template<class RandomIt>
    static void InsertionSort(RandomIt first, RandomIt last) {
        auto func = [](RandomIt lt, RandomIt rt) {
            return *lt > (*rt);
        };
        Arrays::InsertSort<RandomIt>(first, last, func);
    }

    template<class RandomIt>
    static void InsertionSortDesc(RandomIt first, RandomIt last) {
        auto func = [](RandomIt lt, RandomIt rt) {
            return *lt < (*rt);
        };
        Arrays::InsertSort<RandomIt>(first, last, func);
    }

private:
    Arrays();

    template<class RandomIt>
    static void InsertSort(RandomIt first, RandomIt last,
                           std::function<bool (RandomIt, RandomIt)> func) {
        auto length = std::distance(first, last);

        if (length < 2) {
            return;
        }

        RandomIt j = first + 1;

        for (; j != last; ++j) {
            auto key = *j;
            RandomIt i = j - 1;

            while (i >= first && func(i, j)) {
                *(i + 1) = (*i);
                --i;
            }

            *(++i) = key;
        }
    }
};
Sign up to request clarification or add additional context in comments.

2 Comments

You don't have to declare one before the other if you qualify the call with the class name (Arrays::InsertSort). Or, at least G++ accepts the code if the call site qualifies the name.
Thank you, guys, for answer and comments! You helped me very much!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.