How to parametrize an algorithm with a custom non-pure swap-function?












0















I want to apply an algorithm from <algorithms> on ranges of elements, containing in one container, defined by iterator pairs, containing into another one. To do this I need a swap function with state: just pointer to the container with elements to be able to make swaps synchronously in both containers.



This is my incomplete attempt:



#include <utility>
#include <algorithm>
#include <vector>
#include <list>
#include <iostream>
#include <random>

inline
std::ostream & operator << (std::ostream & out, const std::pair< int, int > & p)
{
return out << '{' << p.first << ", " << p.second << '}';
}

int main()
{
using L = std::list< std::pair< int, int > >;
using I = typename L::const_iterator;
using P = std::pair< I, I >;
using R = std::vector< P >;
L values;
R ranges;
auto l = std::cbegin(values);
for (int i = 0; i < 10; ++i) {
l = values.emplace(std::cend(values), i, 0);
auto & p = ranges.emplace_back(l, l);
for (int j = 1; j <= i; ++j) {
p.second = values.emplace(std::cend(values), i, j);
}
}
const auto swap = [&values] (P & l, P & r)
{
auto ll = std::next(l.second);
auto rr = std::next(r.second);
if (ll == r.first) {
values.splice(rr, values, l.first, ll);
} else if (rr == l.first) {
values.splice(ll, values, r.first, rr);
} else {
L temp;
temp.splice(std::cend(temp), values, l.first, ll);
values.splice(ll, values, r.first, rr);
values.splice(rr, std::move(temp));
}
std::swap(l, r);
};
for (const auto & p : values) {
std::cout << p << std::endl;
}
std::cout << "-----" << std::endl;
std::shuffle(std::begin(ranges), std::end(ranges), std::mt19937{std::random_device{}()}); // just an example, it can be any algo, say std::sort w/ custom comparator
for (const auto & p : values) {
std::cout << p << std::endl;
}
}


For sure the swap function object from the above code cannot "participate in overload resolution" (it is oxymoron in the current context because of many reasons, please, do not focus on this).



What I can to do is to define a tagged version of iterator pair in an namespace scope (global (either named or anonymous one, not matters much)) like this using P = struct { std::pair< I, I > p }; and overloading of the free function void swap(P & l, P & r); with the body of the lambda from the code above. Also I surely should to make values a global variable. It leads to hindering of the usefulness of the approach from the code above.



Is there a way to pass a stateful swap function to the algorithms from <algorithm> in a more generic way, then described above?



I read the article and draft about customization points of Eric Niebler. But his approach imply modification of the STL. Either way even if it would be the point his approach cannot allow me to pass stateful overloadings from the function scope, I think, isn't it?










share|improve this question

























  • Rather than ranges being a container of std::pair<I, I>, why not of struct { I first; I second; L & list; }?

    – Caleth
    Nov 23 '18 at 9:17











  • As an aside, all your p.seconds are elements of L of the form i, i. Do you intend that?

    – Caleth
    Nov 23 '18 at 9:25






  • 1





    @Caleth It is one of thinkable solutions, but it leads to extra data duplication.

    – Orient
    Nov 23 '18 at 9:33











  • @Caleth std::pair< int, int > elements are just for example. first is just a number of a range here and the second is an unique value within the range. It is intended for ease of visual distinction. All ranges are of different lengths.

    – Orient
    Nov 23 '18 at 9:40











  • For struct { I first; I second; L * list = {}; } one also need to overload move constructor and move assignment operator to interoperate w/ std::swap properly.

    – Orient
    Nov 23 '18 at 10:28
















0















I want to apply an algorithm from <algorithms> on ranges of elements, containing in one container, defined by iterator pairs, containing into another one. To do this I need a swap function with state: just pointer to the container with elements to be able to make swaps synchronously in both containers.



This is my incomplete attempt:



#include <utility>
#include <algorithm>
#include <vector>
#include <list>
#include <iostream>
#include <random>

inline
std::ostream & operator << (std::ostream & out, const std::pair< int, int > & p)
{
return out << '{' << p.first << ", " << p.second << '}';
}

int main()
{
using L = std::list< std::pair< int, int > >;
using I = typename L::const_iterator;
using P = std::pair< I, I >;
using R = std::vector< P >;
L values;
R ranges;
auto l = std::cbegin(values);
for (int i = 0; i < 10; ++i) {
l = values.emplace(std::cend(values), i, 0);
auto & p = ranges.emplace_back(l, l);
for (int j = 1; j <= i; ++j) {
p.second = values.emplace(std::cend(values), i, j);
}
}
const auto swap = [&values] (P & l, P & r)
{
auto ll = std::next(l.second);
auto rr = std::next(r.second);
if (ll == r.first) {
values.splice(rr, values, l.first, ll);
} else if (rr == l.first) {
values.splice(ll, values, r.first, rr);
} else {
L temp;
temp.splice(std::cend(temp), values, l.first, ll);
values.splice(ll, values, r.first, rr);
values.splice(rr, std::move(temp));
}
std::swap(l, r);
};
for (const auto & p : values) {
std::cout << p << std::endl;
}
std::cout << "-----" << std::endl;
std::shuffle(std::begin(ranges), std::end(ranges), std::mt19937{std::random_device{}()}); // just an example, it can be any algo, say std::sort w/ custom comparator
for (const auto & p : values) {
std::cout << p << std::endl;
}
}


For sure the swap function object from the above code cannot "participate in overload resolution" (it is oxymoron in the current context because of many reasons, please, do not focus on this).



What I can to do is to define a tagged version of iterator pair in an namespace scope (global (either named or anonymous one, not matters much)) like this using P = struct { std::pair< I, I > p }; and overloading of the free function void swap(P & l, P & r); with the body of the lambda from the code above. Also I surely should to make values a global variable. It leads to hindering of the usefulness of the approach from the code above.



Is there a way to pass a stateful swap function to the algorithms from <algorithm> in a more generic way, then described above?



I read the article and draft about customization points of Eric Niebler. But his approach imply modification of the STL. Either way even if it would be the point his approach cannot allow me to pass stateful overloadings from the function scope, I think, isn't it?










share|improve this question

























  • Rather than ranges being a container of std::pair<I, I>, why not of struct { I first; I second; L & list; }?

    – Caleth
    Nov 23 '18 at 9:17











  • As an aside, all your p.seconds are elements of L of the form i, i. Do you intend that?

    – Caleth
    Nov 23 '18 at 9:25






  • 1





    @Caleth It is one of thinkable solutions, but it leads to extra data duplication.

    – Orient
    Nov 23 '18 at 9:33











  • @Caleth std::pair< int, int > elements are just for example. first is just a number of a range here and the second is an unique value within the range. It is intended for ease of visual distinction. All ranges are of different lengths.

    – Orient
    Nov 23 '18 at 9:40











  • For struct { I first; I second; L * list = {}; } one also need to overload move constructor and move assignment operator to interoperate w/ std::swap properly.

    – Orient
    Nov 23 '18 at 10:28














0












0








0








I want to apply an algorithm from <algorithms> on ranges of elements, containing in one container, defined by iterator pairs, containing into another one. To do this I need a swap function with state: just pointer to the container with elements to be able to make swaps synchronously in both containers.



This is my incomplete attempt:



#include <utility>
#include <algorithm>
#include <vector>
#include <list>
#include <iostream>
#include <random>

inline
std::ostream & operator << (std::ostream & out, const std::pair< int, int > & p)
{
return out << '{' << p.first << ", " << p.second << '}';
}

int main()
{
using L = std::list< std::pair< int, int > >;
using I = typename L::const_iterator;
using P = std::pair< I, I >;
using R = std::vector< P >;
L values;
R ranges;
auto l = std::cbegin(values);
for (int i = 0; i < 10; ++i) {
l = values.emplace(std::cend(values), i, 0);
auto & p = ranges.emplace_back(l, l);
for (int j = 1; j <= i; ++j) {
p.second = values.emplace(std::cend(values), i, j);
}
}
const auto swap = [&values] (P & l, P & r)
{
auto ll = std::next(l.second);
auto rr = std::next(r.second);
if (ll == r.first) {
values.splice(rr, values, l.first, ll);
} else if (rr == l.first) {
values.splice(ll, values, r.first, rr);
} else {
L temp;
temp.splice(std::cend(temp), values, l.first, ll);
values.splice(ll, values, r.first, rr);
values.splice(rr, std::move(temp));
}
std::swap(l, r);
};
for (const auto & p : values) {
std::cout << p << std::endl;
}
std::cout << "-----" << std::endl;
std::shuffle(std::begin(ranges), std::end(ranges), std::mt19937{std::random_device{}()}); // just an example, it can be any algo, say std::sort w/ custom comparator
for (const auto & p : values) {
std::cout << p << std::endl;
}
}


For sure the swap function object from the above code cannot "participate in overload resolution" (it is oxymoron in the current context because of many reasons, please, do not focus on this).



What I can to do is to define a tagged version of iterator pair in an namespace scope (global (either named or anonymous one, not matters much)) like this using P = struct { std::pair< I, I > p }; and overloading of the free function void swap(P & l, P & r); with the body of the lambda from the code above. Also I surely should to make values a global variable. It leads to hindering of the usefulness of the approach from the code above.



Is there a way to pass a stateful swap function to the algorithms from <algorithm> in a more generic way, then described above?



I read the article and draft about customization points of Eric Niebler. But his approach imply modification of the STL. Either way even if it would be the point his approach cannot allow me to pass stateful overloadings from the function scope, I think, isn't it?










share|improve this question
















I want to apply an algorithm from <algorithms> on ranges of elements, containing in one container, defined by iterator pairs, containing into another one. To do this I need a swap function with state: just pointer to the container with elements to be able to make swaps synchronously in both containers.



This is my incomplete attempt:



#include <utility>
#include <algorithm>
#include <vector>
#include <list>
#include <iostream>
#include <random>

inline
std::ostream & operator << (std::ostream & out, const std::pair< int, int > & p)
{
return out << '{' << p.first << ", " << p.second << '}';
}

int main()
{
using L = std::list< std::pair< int, int > >;
using I = typename L::const_iterator;
using P = std::pair< I, I >;
using R = std::vector< P >;
L values;
R ranges;
auto l = std::cbegin(values);
for (int i = 0; i < 10; ++i) {
l = values.emplace(std::cend(values), i, 0);
auto & p = ranges.emplace_back(l, l);
for (int j = 1; j <= i; ++j) {
p.second = values.emplace(std::cend(values), i, j);
}
}
const auto swap = [&values] (P & l, P & r)
{
auto ll = std::next(l.second);
auto rr = std::next(r.second);
if (ll == r.first) {
values.splice(rr, values, l.first, ll);
} else if (rr == l.first) {
values.splice(ll, values, r.first, rr);
} else {
L temp;
temp.splice(std::cend(temp), values, l.first, ll);
values.splice(ll, values, r.first, rr);
values.splice(rr, std::move(temp));
}
std::swap(l, r);
};
for (const auto & p : values) {
std::cout << p << std::endl;
}
std::cout << "-----" << std::endl;
std::shuffle(std::begin(ranges), std::end(ranges), std::mt19937{std::random_device{}()}); // just an example, it can be any algo, say std::sort w/ custom comparator
for (const auto & p : values) {
std::cout << p << std::endl;
}
}


For sure the swap function object from the above code cannot "participate in overload resolution" (it is oxymoron in the current context because of many reasons, please, do not focus on this).



What I can to do is to define a tagged version of iterator pair in an namespace scope (global (either named or anonymous one, not matters much)) like this using P = struct { std::pair< I, I > p }; and overloading of the free function void swap(P & l, P & r); with the body of the lambda from the code above. Also I surely should to make values a global variable. It leads to hindering of the usefulness of the approach from the code above.



Is there a way to pass a stateful swap function to the algorithms from <algorithm> in a more generic way, then described above?



I read the article and draft about customization points of Eric Niebler. But his approach imply modification of the STL. Either way even if it would be the point his approach cannot allow me to pass stateful overloadings from the function scope, I think, isn't it?







c++ algorithm lambda stl overload-resolution






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 23 '18 at 12:24







Orient

















asked Nov 23 '18 at 9:07









OrientOrient

6,26153295




6,26153295













  • Rather than ranges being a container of std::pair<I, I>, why not of struct { I first; I second; L & list; }?

    – Caleth
    Nov 23 '18 at 9:17











  • As an aside, all your p.seconds are elements of L of the form i, i. Do you intend that?

    – Caleth
    Nov 23 '18 at 9:25






  • 1





    @Caleth It is one of thinkable solutions, but it leads to extra data duplication.

    – Orient
    Nov 23 '18 at 9:33











  • @Caleth std::pair< int, int > elements are just for example. first is just a number of a range here and the second is an unique value within the range. It is intended for ease of visual distinction. All ranges are of different lengths.

    – Orient
    Nov 23 '18 at 9:40











  • For struct { I first; I second; L * list = {}; } one also need to overload move constructor and move assignment operator to interoperate w/ std::swap properly.

    – Orient
    Nov 23 '18 at 10:28



















  • Rather than ranges being a container of std::pair<I, I>, why not of struct { I first; I second; L & list; }?

    – Caleth
    Nov 23 '18 at 9:17











  • As an aside, all your p.seconds are elements of L of the form i, i. Do you intend that?

    – Caleth
    Nov 23 '18 at 9:25






  • 1





    @Caleth It is one of thinkable solutions, but it leads to extra data duplication.

    – Orient
    Nov 23 '18 at 9:33











  • @Caleth std::pair< int, int > elements are just for example. first is just a number of a range here and the second is an unique value within the range. It is intended for ease of visual distinction. All ranges are of different lengths.

    – Orient
    Nov 23 '18 at 9:40











  • For struct { I first; I second; L * list = {}; } one also need to overload move constructor and move assignment operator to interoperate w/ std::swap properly.

    – Orient
    Nov 23 '18 at 10:28

















Rather than ranges being a container of std::pair<I, I>, why not of struct { I first; I second; L & list; }?

– Caleth
Nov 23 '18 at 9:17





Rather than ranges being a container of std::pair<I, I>, why not of struct { I first; I second; L & list; }?

– Caleth
Nov 23 '18 at 9:17













As an aside, all your p.seconds are elements of L of the form i, i. Do you intend that?

– Caleth
Nov 23 '18 at 9:25





As an aside, all your p.seconds are elements of L of the form i, i. Do you intend that?

– Caleth
Nov 23 '18 at 9:25




1




1





@Caleth It is one of thinkable solutions, but it leads to extra data duplication.

– Orient
Nov 23 '18 at 9:33





@Caleth It is one of thinkable solutions, but it leads to extra data duplication.

– Orient
Nov 23 '18 at 9:33













@Caleth std::pair< int, int > elements are just for example. first is just a number of a range here and the second is an unique value within the range. It is intended for ease of visual distinction. All ranges are of different lengths.

– Orient
Nov 23 '18 at 9:40





@Caleth std::pair< int, int > elements are just for example. first is just a number of a range here and the second is an unique value within the range. It is intended for ease of visual distinction. All ranges are of different lengths.

– Orient
Nov 23 '18 at 9:40













For struct { I first; I second; L * list = {}; } one also need to overload move constructor and move assignment operator to interoperate w/ std::swap properly.

– Orient
Nov 23 '18 at 10:28





For struct { I first; I second; L * list = {}; } one also need to overload move constructor and move assignment operator to interoperate w/ std::swap properly.

– Orient
Nov 23 '18 at 10:28












2 Answers
2






active

oldest

votes


















1














You can just include values in your range object.



struct Range { I first; I second; L & list; }

void swap(Range & l, Range & r)
{
assert(std::addressof(l.list) == std::addressof(r.list));
using std::swap;

auto ll = std::next(l.second);
auto rr = std::next(r.second);
if (ll == r.first) {
l.list.splice(rr, l.list, l.first, ll);
} else if (rr == l.first) {
l.list.splice(ll, l.list, r.first, rr);
} else {
L temp;
temp.splice(std::cend(temp), l.list, l.first, ll);
l.list.splice(ll, l.list, r.first, rr);
l.list.splice(rr, std::move(temp));
}
swap(l.first, r.first);
swap(l.second, r.second);
}





share|improve this answer
























  • You meant defining the free function. I like your solution.

    – Orient
    Nov 23 '18 at 10:41



















0














I find a better way (if compare with ones based on swap function overloading) to implement desired: two-pass way to apply changes. It gives just linear overhead, instead of the algorithm of interest's complexity.



#include <utility>
#include <algorithm>
#include <vector>
#include <list>
#include <iostream>
#include <random>
#include <cassert>

inline
std::ostream & operator << (std::ostream & out, const std::pair< int, int > & p)
{
return out << '{' << p.first << ", " << p.second << '}';
}

int main()
{
using L = std::list< std::pair< int, int > >;
using I = typename L::const_iterator;
using P = std::pair< I, I >;
using R = std::vector< P >;
L values;
R ranges;
auto l = std::cbegin(values);
for (int i = 0; i < 10; ++i) {
l = values.emplace(std::cend(values), i, 0);
auto & p = ranges.emplace_back(l, l);
for (int j = 1; j <= i; ++j) {
p.second = values.emplace(std::cend(values), i, j);
}
}
for (const auto & p : values) {
std::cout << p << std::endl;
}
std::cout << "-----" << std::endl;
std::shuffle(std::begin(ranges), std::end(ranges), std::mt19937{std::random_device{}()});
l = std::cbegin(values);
for (const auto & range : ranges) {
auto r = std::next(range.second);
if (l != range.first) {
values.splice(l, values, range.first, r);
}
l = r;
}
assert(l == std::cend(values));
for (const auto & p : values) {
std::cout << p << std::endl;
}
}


Don't think it can be applicable to containers with somehow stricter iterators invalidation rules.






share|improve this answer

























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53443555%2fhow-to-parametrize-an-algorithm-with-a-custom-non-pure-swap-function%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    You can just include values in your range object.



    struct Range { I first; I second; L & list; }

    void swap(Range & l, Range & r)
    {
    assert(std::addressof(l.list) == std::addressof(r.list));
    using std::swap;

    auto ll = std::next(l.second);
    auto rr = std::next(r.second);
    if (ll == r.first) {
    l.list.splice(rr, l.list, l.first, ll);
    } else if (rr == l.first) {
    l.list.splice(ll, l.list, r.first, rr);
    } else {
    L temp;
    temp.splice(std::cend(temp), l.list, l.first, ll);
    l.list.splice(ll, l.list, r.first, rr);
    l.list.splice(rr, std::move(temp));
    }
    swap(l.first, r.first);
    swap(l.second, r.second);
    }





    share|improve this answer
























    • You meant defining the free function. I like your solution.

      – Orient
      Nov 23 '18 at 10:41
















    1














    You can just include values in your range object.



    struct Range { I first; I second; L & list; }

    void swap(Range & l, Range & r)
    {
    assert(std::addressof(l.list) == std::addressof(r.list));
    using std::swap;

    auto ll = std::next(l.second);
    auto rr = std::next(r.second);
    if (ll == r.first) {
    l.list.splice(rr, l.list, l.first, ll);
    } else if (rr == l.first) {
    l.list.splice(ll, l.list, r.first, rr);
    } else {
    L temp;
    temp.splice(std::cend(temp), l.list, l.first, ll);
    l.list.splice(ll, l.list, r.first, rr);
    l.list.splice(rr, std::move(temp));
    }
    swap(l.first, r.first);
    swap(l.second, r.second);
    }





    share|improve this answer
























    • You meant defining the free function. I like your solution.

      – Orient
      Nov 23 '18 at 10:41














    1












    1








    1







    You can just include values in your range object.



    struct Range { I first; I second; L & list; }

    void swap(Range & l, Range & r)
    {
    assert(std::addressof(l.list) == std::addressof(r.list));
    using std::swap;

    auto ll = std::next(l.second);
    auto rr = std::next(r.second);
    if (ll == r.first) {
    l.list.splice(rr, l.list, l.first, ll);
    } else if (rr == l.first) {
    l.list.splice(ll, l.list, r.first, rr);
    } else {
    L temp;
    temp.splice(std::cend(temp), l.list, l.first, ll);
    l.list.splice(ll, l.list, r.first, rr);
    l.list.splice(rr, std::move(temp));
    }
    swap(l.first, r.first);
    swap(l.second, r.second);
    }





    share|improve this answer













    You can just include values in your range object.



    struct Range { I first; I second; L & list; }

    void swap(Range & l, Range & r)
    {
    assert(std::addressof(l.list) == std::addressof(r.list));
    using std::swap;

    auto ll = std::next(l.second);
    auto rr = std::next(r.second);
    if (ll == r.first) {
    l.list.splice(rr, l.list, l.first, ll);
    } else if (rr == l.first) {
    l.list.splice(ll, l.list, r.first, rr);
    } else {
    L temp;
    temp.splice(std::cend(temp), l.list, l.first, ll);
    l.list.splice(ll, l.list, r.first, rr);
    l.list.splice(rr, std::move(temp));
    }
    swap(l.first, r.first);
    swap(l.second, r.second);
    }






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 23 '18 at 10:38









    CalethCaleth

    17.3k22139




    17.3k22139













    • You meant defining the free function. I like your solution.

      – Orient
      Nov 23 '18 at 10:41



















    • You meant defining the free function. I like your solution.

      – Orient
      Nov 23 '18 at 10:41

















    You meant defining the free function. I like your solution.

    – Orient
    Nov 23 '18 at 10:41





    You meant defining the free function. I like your solution.

    – Orient
    Nov 23 '18 at 10:41













    0














    I find a better way (if compare with ones based on swap function overloading) to implement desired: two-pass way to apply changes. It gives just linear overhead, instead of the algorithm of interest's complexity.



    #include <utility>
    #include <algorithm>
    #include <vector>
    #include <list>
    #include <iostream>
    #include <random>
    #include <cassert>

    inline
    std::ostream & operator << (std::ostream & out, const std::pair< int, int > & p)
    {
    return out << '{' << p.first << ", " << p.second << '}';
    }

    int main()
    {
    using L = std::list< std::pair< int, int > >;
    using I = typename L::const_iterator;
    using P = std::pair< I, I >;
    using R = std::vector< P >;
    L values;
    R ranges;
    auto l = std::cbegin(values);
    for (int i = 0; i < 10; ++i) {
    l = values.emplace(std::cend(values), i, 0);
    auto & p = ranges.emplace_back(l, l);
    for (int j = 1; j <= i; ++j) {
    p.second = values.emplace(std::cend(values), i, j);
    }
    }
    for (const auto & p : values) {
    std::cout << p << std::endl;
    }
    std::cout << "-----" << std::endl;
    std::shuffle(std::begin(ranges), std::end(ranges), std::mt19937{std::random_device{}()});
    l = std::cbegin(values);
    for (const auto & range : ranges) {
    auto r = std::next(range.second);
    if (l != range.first) {
    values.splice(l, values, range.first, r);
    }
    l = r;
    }
    assert(l == std::cend(values));
    for (const auto & p : values) {
    std::cout << p << std::endl;
    }
    }


    Don't think it can be applicable to containers with somehow stricter iterators invalidation rules.






    share|improve this answer






























      0














      I find a better way (if compare with ones based on swap function overloading) to implement desired: two-pass way to apply changes. It gives just linear overhead, instead of the algorithm of interest's complexity.



      #include <utility>
      #include <algorithm>
      #include <vector>
      #include <list>
      #include <iostream>
      #include <random>
      #include <cassert>

      inline
      std::ostream & operator << (std::ostream & out, const std::pair< int, int > & p)
      {
      return out << '{' << p.first << ", " << p.second << '}';
      }

      int main()
      {
      using L = std::list< std::pair< int, int > >;
      using I = typename L::const_iterator;
      using P = std::pair< I, I >;
      using R = std::vector< P >;
      L values;
      R ranges;
      auto l = std::cbegin(values);
      for (int i = 0; i < 10; ++i) {
      l = values.emplace(std::cend(values), i, 0);
      auto & p = ranges.emplace_back(l, l);
      for (int j = 1; j <= i; ++j) {
      p.second = values.emplace(std::cend(values), i, j);
      }
      }
      for (const auto & p : values) {
      std::cout << p << std::endl;
      }
      std::cout << "-----" << std::endl;
      std::shuffle(std::begin(ranges), std::end(ranges), std::mt19937{std::random_device{}()});
      l = std::cbegin(values);
      for (const auto & range : ranges) {
      auto r = std::next(range.second);
      if (l != range.first) {
      values.splice(l, values, range.first, r);
      }
      l = r;
      }
      assert(l == std::cend(values));
      for (const auto & p : values) {
      std::cout << p << std::endl;
      }
      }


      Don't think it can be applicable to containers with somehow stricter iterators invalidation rules.






      share|improve this answer




























        0












        0








        0







        I find a better way (if compare with ones based on swap function overloading) to implement desired: two-pass way to apply changes. It gives just linear overhead, instead of the algorithm of interest's complexity.



        #include <utility>
        #include <algorithm>
        #include <vector>
        #include <list>
        #include <iostream>
        #include <random>
        #include <cassert>

        inline
        std::ostream & operator << (std::ostream & out, const std::pair< int, int > & p)
        {
        return out << '{' << p.first << ", " << p.second << '}';
        }

        int main()
        {
        using L = std::list< std::pair< int, int > >;
        using I = typename L::const_iterator;
        using P = std::pair< I, I >;
        using R = std::vector< P >;
        L values;
        R ranges;
        auto l = std::cbegin(values);
        for (int i = 0; i < 10; ++i) {
        l = values.emplace(std::cend(values), i, 0);
        auto & p = ranges.emplace_back(l, l);
        for (int j = 1; j <= i; ++j) {
        p.second = values.emplace(std::cend(values), i, j);
        }
        }
        for (const auto & p : values) {
        std::cout << p << std::endl;
        }
        std::cout << "-----" << std::endl;
        std::shuffle(std::begin(ranges), std::end(ranges), std::mt19937{std::random_device{}()});
        l = std::cbegin(values);
        for (const auto & range : ranges) {
        auto r = std::next(range.second);
        if (l != range.first) {
        values.splice(l, values, range.first, r);
        }
        l = r;
        }
        assert(l == std::cend(values));
        for (const auto & p : values) {
        std::cout << p << std::endl;
        }
        }


        Don't think it can be applicable to containers with somehow stricter iterators invalidation rules.






        share|improve this answer















        I find a better way (if compare with ones based on swap function overloading) to implement desired: two-pass way to apply changes. It gives just linear overhead, instead of the algorithm of interest's complexity.



        #include <utility>
        #include <algorithm>
        #include <vector>
        #include <list>
        #include <iostream>
        #include <random>
        #include <cassert>

        inline
        std::ostream & operator << (std::ostream & out, const std::pair< int, int > & p)
        {
        return out << '{' << p.first << ", " << p.second << '}';
        }

        int main()
        {
        using L = std::list< std::pair< int, int > >;
        using I = typename L::const_iterator;
        using P = std::pair< I, I >;
        using R = std::vector< P >;
        L values;
        R ranges;
        auto l = std::cbegin(values);
        for (int i = 0; i < 10; ++i) {
        l = values.emplace(std::cend(values), i, 0);
        auto & p = ranges.emplace_back(l, l);
        for (int j = 1; j <= i; ++j) {
        p.second = values.emplace(std::cend(values), i, j);
        }
        }
        for (const auto & p : values) {
        std::cout << p << std::endl;
        }
        std::cout << "-----" << std::endl;
        std::shuffle(std::begin(ranges), std::end(ranges), std::mt19937{std::random_device{}()});
        l = std::cbegin(values);
        for (const auto & range : ranges) {
        auto r = std::next(range.second);
        if (l != range.first) {
        values.splice(l, values, range.first, r);
        }
        l = r;
        }
        assert(l == std::cend(values));
        for (const auto & p : values) {
        std::cout << p << std::endl;
        }
        }


        Don't think it can be applicable to containers with somehow stricter iterators invalidation rules.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 23 '18 at 10:49

























        answered Nov 23 '18 at 10:43









        OrientOrient

        6,26153295




        6,26153295






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53443555%2fhow-to-parametrize-an-algorithm-with-a-custom-non-pure-swap-function%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Create new schema in PostgreSQL using DBeaver

            Deepest pit of an array with Javascript: test on Codility

            Costa Masnaga