Improvement for std::map double dispatch












5














I am trying to do my c++ homework and as a part of it I have to implement a std::map with an int as its key and a value should be a specific void function, which prints some text.
I can`t find an answer to what are the correct ways of doing that.



This is what I have so far:



#include <map>
#include <string>
#include <iostream>

class testClass
{
public:
void testFunc1() { std::cout << "func1n"; }
void testFunc2() { std::cout << "func2n"; }
};

typedef void(testClass::*runFunc)(void);
typedef std::map<int, runFunc> myMapType;

int main() {
testClass t1;

std::map<int, runFunc> myMap;
myMap.emplace(1, &testClass::testFunc1);
myMap.emplace(2, &testClass::testFunc2);

myMapType::const_iterator itr;
itr = myMap.find(2);

if (itr != myMap.end()) {
(t1.*(itr->second))();
}
}


The code is working now, however I am not sure if that is the way people with more experience do.



Also, if you are aware of any sources where one can read more about knowledge required to achieve the needed result - any ideas are appreciated.










share|improve this question









New contributor




Gasper J. is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
















  • 1




    If your code is a simplified version of what you really have to do, then it's off-topic and this question needs to be closed; per codereview.stackexchange.com/help/on-topic - "In order to give good advice, we need to see real, concrete code, and understand the context in which the code is used. Generic code (such as code containing placeholders like foo, MyClass, or doSomething()) leaves too much to the imagination."
    – Reinderien
    Dec 26 at 21:51
















5














I am trying to do my c++ homework and as a part of it I have to implement a std::map with an int as its key and a value should be a specific void function, which prints some text.
I can`t find an answer to what are the correct ways of doing that.



This is what I have so far:



#include <map>
#include <string>
#include <iostream>

class testClass
{
public:
void testFunc1() { std::cout << "func1n"; }
void testFunc2() { std::cout << "func2n"; }
};

typedef void(testClass::*runFunc)(void);
typedef std::map<int, runFunc> myMapType;

int main() {
testClass t1;

std::map<int, runFunc> myMap;
myMap.emplace(1, &testClass::testFunc1);
myMap.emplace(2, &testClass::testFunc2);

myMapType::const_iterator itr;
itr = myMap.find(2);

if (itr != myMap.end()) {
(t1.*(itr->second))();
}
}


The code is working now, however I am not sure if that is the way people with more experience do.



Also, if you are aware of any sources where one can read more about knowledge required to achieve the needed result - any ideas are appreciated.










share|improve this question









New contributor




Gasper J. is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
















  • 1




    If your code is a simplified version of what you really have to do, then it's off-topic and this question needs to be closed; per codereview.stackexchange.com/help/on-topic - "In order to give good advice, we need to see real, concrete code, and understand the context in which the code is used. Generic code (such as code containing placeholders like foo, MyClass, or doSomething()) leaves too much to the imagination."
    – Reinderien
    Dec 26 at 21:51














5












5








5


2





I am trying to do my c++ homework and as a part of it I have to implement a std::map with an int as its key and a value should be a specific void function, which prints some text.
I can`t find an answer to what are the correct ways of doing that.



This is what I have so far:



#include <map>
#include <string>
#include <iostream>

class testClass
{
public:
void testFunc1() { std::cout << "func1n"; }
void testFunc2() { std::cout << "func2n"; }
};

typedef void(testClass::*runFunc)(void);
typedef std::map<int, runFunc> myMapType;

int main() {
testClass t1;

std::map<int, runFunc> myMap;
myMap.emplace(1, &testClass::testFunc1);
myMap.emplace(2, &testClass::testFunc2);

myMapType::const_iterator itr;
itr = myMap.find(2);

if (itr != myMap.end()) {
(t1.*(itr->second))();
}
}


The code is working now, however I am not sure if that is the way people with more experience do.



Also, if you are aware of any sources where one can read more about knowledge required to achieve the needed result - any ideas are appreciated.










share|improve this question









New contributor




Gasper J. is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











I am trying to do my c++ homework and as a part of it I have to implement a std::map with an int as its key and a value should be a specific void function, which prints some text.
I can`t find an answer to what are the correct ways of doing that.



This is what I have so far:



#include <map>
#include <string>
#include <iostream>

class testClass
{
public:
void testFunc1() { std::cout << "func1n"; }
void testFunc2() { std::cout << "func2n"; }
};

typedef void(testClass::*runFunc)(void);
typedef std::map<int, runFunc> myMapType;

int main() {
testClass t1;

std::map<int, runFunc> myMap;
myMap.emplace(1, &testClass::testFunc1);
myMap.emplace(2, &testClass::testFunc2);

myMapType::const_iterator itr;
itr = myMap.find(2);

if (itr != myMap.end()) {
(t1.*(itr->second))();
}
}


The code is working now, however I am not sure if that is the way people with more experience do.



Also, if you are aware of any sources where one can read more about knowledge required to achieve the needed result - any ideas are appreciated.







c++






share|improve this question









New contributor




Gasper J. is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




Gasper J. is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited Dec 26 at 14:28





















New contributor




Gasper J. is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked Dec 26 at 13:01









Gasper J.

314




314




New contributor




Gasper J. is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





Gasper J. is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






Gasper J. is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.








  • 1




    If your code is a simplified version of what you really have to do, then it's off-topic and this question needs to be closed; per codereview.stackexchange.com/help/on-topic - "In order to give good advice, we need to see real, concrete code, and understand the context in which the code is used. Generic code (such as code containing placeholders like foo, MyClass, or doSomething()) leaves too much to the imagination."
    – Reinderien
    Dec 26 at 21:51














  • 1




    If your code is a simplified version of what you really have to do, then it's off-topic and this question needs to be closed; per codereview.stackexchange.com/help/on-topic - "In order to give good advice, we need to see real, concrete code, and understand the context in which the code is used. Generic code (such as code containing placeholders like foo, MyClass, or doSomething()) leaves too much to the imagination."
    – Reinderien
    Dec 26 at 21:51








1




1




If your code is a simplified version of what you really have to do, then it's off-topic and this question needs to be closed; per codereview.stackexchange.com/help/on-topic - "In order to give good advice, we need to see real, concrete code, and understand the context in which the code is used. Generic code (such as code containing placeholders like foo, MyClass, or doSomething()) leaves too much to the imagination."
– Reinderien
Dec 26 at 21:51




If your code is a simplified version of what you really have to do, then it's off-topic and this question needs to be closed; per codereview.stackexchange.com/help/on-topic - "In order to give good advice, we need to see real, concrete code, and understand the context in which the code is used. Generic code (such as code containing placeholders like foo, MyClass, or doSomething()) leaves too much to the imagination."
– Reinderien
Dec 26 at 21:51










3 Answers
3






active

oldest

votes


















2














As other answers have already said, the trick you're looking for is called std::function, and it's defined in the standard <functional> header.



You include <string> but never use it. You define myMapType but never use it.



Unless you need portability back to C++03, you should use using X = Y; in place of typedef Y X;.



A common name for "scratch" iterator variables is it (not to be confused with i for integer indices). Your itr is reasonably clear, but not idiomatic.





Following the dictum that "good C++ code should look like Python," I'd write your program like this:



#include <cstdio>
#include <functional>
#include <map>

void testFunc1() {
puts("func1");
}
void testFunc2() {
puts("func2");
}

using MapType = std::map<int, std::function<void()>>;

int main() {
MapType myMap = {
{ 1, testFunc1 },
{ 2, testFunc2 },
};

auto it = myMap.find(2);
if (it != myMap.end()) {
it->second();
}
}




Instead of the map initializer I wrote, you could write



MapType myMap;
myMap[1] = testFunc1;
myMap[2] = testFunc2;


but I strongly recommend "declarative" over "imperative." "Declarative" style means to define the whole map at once, as a data object, in the state you want it; "imperative" style means to define an empty map and then repeatedly mutate it so as to eventually arrive at the state you want. "Declarative" tends to be easier to reason about.






share|improve this answer





























    4














    In general your code looks good. But I have some little annotations (improvements) for you.



    1. I'd prefer direct initialization of itr for sake of readability:



    myMapType::const_iterator itr = myMap.find(2);


    instead of



    myMapType::const_iterator itr;
    itr = myMap.find(2);


    That said you could also avoid



    typedef std::map<int, runFunc> myMapType;


    completely using the auto keyword:



    auto itr = myMap.find(2);


    2. Make use std::function and lambda bindings



    For the callable value parameter of the std::map I'd prefer to use an appropriate std::function value type and lambda function bindings to the instance to operate on.



    testClass t1;

    std::map<int, std::function<void()>> myMap;
    myMap.emplace(1, [&t1](){t1.testFunc1();});
    myMap.emplace(2, [&t1](){t1.testFunc2();});


    This will give you greater flexibility for later changes and use of other classes than just testClass. Also you can get rid of that other type definition then:



    typedef void(testClass::*runFunc)(void);


    As soon you want to use your map for the general case you can clearly see the benefits:



    class A {
    public:
    void print() { std::cout << "print() from class A.n"; }
    };

    class B {
    public:
    void print() { std::cout << "print() from class B.n"; }
    };

    // ...
    int main() {
    A a;
    B b;

    std::map<int, std::function<void()>> myMap;
    myMap.emplace(1, [&a](){a.print();});
    myMap.emplace(2, [&b](){b.print();});

    }




    Here's my set of changes in whole (you can check it's still working as intended here):



    #include <map>
    #include <string>
    #include <iostream>
    #include <functional>

    class testClass
    {
    public:
    void testFunc1() { std::cout << "func1n"; }
    void testFunc2() { std::cout << "func2n"; }
    };

    int main() {
    testClass t1;

    std::map<int, std::function<void()>> myMap;
    myMap.emplace(1, [&t1](){t1.testFunc1();});
    myMap.emplace(2, [&t1](){t1.testFunc2();});

    auto itr = myMap.find(2);

    if (itr != myMap.end()) {
    (itr->second)();
    }
    }





    share|improve this answer























    • Instead of a lambda that calls the function you can use std::bind.
      – Emily L.
      Dec 26 at 15:55






    • 2




      @EmilyL. But lambdas are preferred over std::bind! There is no need for it now. Lambdas are far more expressive.
      – Lightness Races in Orbit
      Dec 27 at 2:33










    • @lightnessracesinorbit that's the first I've heard, can you give a reference? I still feel like bind is better expressing the intent
      – Emily L.
      Dec 27 at 12:24






    • 2




      @EmilyL. Sure! stackoverflow.com/a/17545183/560648
      – Lightness Races in Orbit
      Dec 27 at 14:02



















    0














    Given your current test code, there's no reason for testClass to exist. Your two test functions can simply be functions in the global namespace, and then your emplace calls can be simplified.



    void testFunc1() { std::cout << "func1n"; }
    void testFunc2() { std::cout << "func2n"; }

    typedef void(*runFunc)(void);
    // ...

    myMap.emplace(1, testFunc1);
    myMap.emplace(2, testFunc2);





    share|improve this answer





















    • thanks for your suggestion. my code above is a simplified version of what I really have to do. with just global functions it won't go.
      – Gasper J.
      Dec 26 at 18:40










    • See comments on question, in that case. This is off-topic.
      – Reinderien
      Dec 26 at 21:52











    Your Answer





    StackExchange.ifUsing("editor", function () {
    return StackExchange.using("mathjaxEditing", function () {
    StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
    StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
    });
    });
    }, "mathjax-editing");

    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: "196"
    };
    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: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    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
    });


    }
    });






    Gasper J. is a new contributor. Be nice, and check out our Code of Conduct.










    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210356%2fimprovement-for-stdmap-int-run-some-function-double-dispatch%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    2














    As other answers have already said, the trick you're looking for is called std::function, and it's defined in the standard <functional> header.



    You include <string> but never use it. You define myMapType but never use it.



    Unless you need portability back to C++03, you should use using X = Y; in place of typedef Y X;.



    A common name for "scratch" iterator variables is it (not to be confused with i for integer indices). Your itr is reasonably clear, but not idiomatic.





    Following the dictum that "good C++ code should look like Python," I'd write your program like this:



    #include <cstdio>
    #include <functional>
    #include <map>

    void testFunc1() {
    puts("func1");
    }
    void testFunc2() {
    puts("func2");
    }

    using MapType = std::map<int, std::function<void()>>;

    int main() {
    MapType myMap = {
    { 1, testFunc1 },
    { 2, testFunc2 },
    };

    auto it = myMap.find(2);
    if (it != myMap.end()) {
    it->second();
    }
    }




    Instead of the map initializer I wrote, you could write



    MapType myMap;
    myMap[1] = testFunc1;
    myMap[2] = testFunc2;


    but I strongly recommend "declarative" over "imperative." "Declarative" style means to define the whole map at once, as a data object, in the state you want it; "imperative" style means to define an empty map and then repeatedly mutate it so as to eventually arrive at the state you want. "Declarative" tends to be easier to reason about.






    share|improve this answer


























      2














      As other answers have already said, the trick you're looking for is called std::function, and it's defined in the standard <functional> header.



      You include <string> but never use it. You define myMapType but never use it.



      Unless you need portability back to C++03, you should use using X = Y; in place of typedef Y X;.



      A common name for "scratch" iterator variables is it (not to be confused with i for integer indices). Your itr is reasonably clear, but not idiomatic.





      Following the dictum that "good C++ code should look like Python," I'd write your program like this:



      #include <cstdio>
      #include <functional>
      #include <map>

      void testFunc1() {
      puts("func1");
      }
      void testFunc2() {
      puts("func2");
      }

      using MapType = std::map<int, std::function<void()>>;

      int main() {
      MapType myMap = {
      { 1, testFunc1 },
      { 2, testFunc2 },
      };

      auto it = myMap.find(2);
      if (it != myMap.end()) {
      it->second();
      }
      }




      Instead of the map initializer I wrote, you could write



      MapType myMap;
      myMap[1] = testFunc1;
      myMap[2] = testFunc2;


      but I strongly recommend "declarative" over "imperative." "Declarative" style means to define the whole map at once, as a data object, in the state you want it; "imperative" style means to define an empty map and then repeatedly mutate it so as to eventually arrive at the state you want. "Declarative" tends to be easier to reason about.






      share|improve this answer
























        2












        2








        2






        As other answers have already said, the trick you're looking for is called std::function, and it's defined in the standard <functional> header.



        You include <string> but never use it. You define myMapType but never use it.



        Unless you need portability back to C++03, you should use using X = Y; in place of typedef Y X;.



        A common name for "scratch" iterator variables is it (not to be confused with i for integer indices). Your itr is reasonably clear, but not idiomatic.





        Following the dictum that "good C++ code should look like Python," I'd write your program like this:



        #include <cstdio>
        #include <functional>
        #include <map>

        void testFunc1() {
        puts("func1");
        }
        void testFunc2() {
        puts("func2");
        }

        using MapType = std::map<int, std::function<void()>>;

        int main() {
        MapType myMap = {
        { 1, testFunc1 },
        { 2, testFunc2 },
        };

        auto it = myMap.find(2);
        if (it != myMap.end()) {
        it->second();
        }
        }




        Instead of the map initializer I wrote, you could write



        MapType myMap;
        myMap[1] = testFunc1;
        myMap[2] = testFunc2;


        but I strongly recommend "declarative" over "imperative." "Declarative" style means to define the whole map at once, as a data object, in the state you want it; "imperative" style means to define an empty map and then repeatedly mutate it so as to eventually arrive at the state you want. "Declarative" tends to be easier to reason about.






        share|improve this answer












        As other answers have already said, the trick you're looking for is called std::function, and it's defined in the standard <functional> header.



        You include <string> but never use it. You define myMapType but never use it.



        Unless you need portability back to C++03, you should use using X = Y; in place of typedef Y X;.



        A common name for "scratch" iterator variables is it (not to be confused with i for integer indices). Your itr is reasonably clear, but not idiomatic.





        Following the dictum that "good C++ code should look like Python," I'd write your program like this:



        #include <cstdio>
        #include <functional>
        #include <map>

        void testFunc1() {
        puts("func1");
        }
        void testFunc2() {
        puts("func2");
        }

        using MapType = std::map<int, std::function<void()>>;

        int main() {
        MapType myMap = {
        { 1, testFunc1 },
        { 2, testFunc2 },
        };

        auto it = myMap.find(2);
        if (it != myMap.end()) {
        it->second();
        }
        }




        Instead of the map initializer I wrote, you could write



        MapType myMap;
        myMap[1] = testFunc1;
        myMap[2] = testFunc2;


        but I strongly recommend "declarative" over "imperative." "Declarative" style means to define the whole map at once, as a data object, in the state you want it; "imperative" style means to define an empty map and then repeatedly mutate it so as to eventually arrive at the state you want. "Declarative" tends to be easier to reason about.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Dec 27 at 2:06









        Quuxplusone

        11.3k11959




        11.3k11959

























            4














            In general your code looks good. But I have some little annotations (improvements) for you.



            1. I'd prefer direct initialization of itr for sake of readability:



            myMapType::const_iterator itr = myMap.find(2);


            instead of



            myMapType::const_iterator itr;
            itr = myMap.find(2);


            That said you could also avoid



            typedef std::map<int, runFunc> myMapType;


            completely using the auto keyword:



            auto itr = myMap.find(2);


            2. Make use std::function and lambda bindings



            For the callable value parameter of the std::map I'd prefer to use an appropriate std::function value type and lambda function bindings to the instance to operate on.



            testClass t1;

            std::map<int, std::function<void()>> myMap;
            myMap.emplace(1, [&t1](){t1.testFunc1();});
            myMap.emplace(2, [&t1](){t1.testFunc2();});


            This will give you greater flexibility for later changes and use of other classes than just testClass. Also you can get rid of that other type definition then:



            typedef void(testClass::*runFunc)(void);


            As soon you want to use your map for the general case you can clearly see the benefits:



            class A {
            public:
            void print() { std::cout << "print() from class A.n"; }
            };

            class B {
            public:
            void print() { std::cout << "print() from class B.n"; }
            };

            // ...
            int main() {
            A a;
            B b;

            std::map<int, std::function<void()>> myMap;
            myMap.emplace(1, [&a](){a.print();});
            myMap.emplace(2, [&b](){b.print();});

            }




            Here's my set of changes in whole (you can check it's still working as intended here):



            #include <map>
            #include <string>
            #include <iostream>
            #include <functional>

            class testClass
            {
            public:
            void testFunc1() { std::cout << "func1n"; }
            void testFunc2() { std::cout << "func2n"; }
            };

            int main() {
            testClass t1;

            std::map<int, std::function<void()>> myMap;
            myMap.emplace(1, [&t1](){t1.testFunc1();});
            myMap.emplace(2, [&t1](){t1.testFunc2();});

            auto itr = myMap.find(2);

            if (itr != myMap.end()) {
            (itr->second)();
            }
            }





            share|improve this answer























            • Instead of a lambda that calls the function you can use std::bind.
              – Emily L.
              Dec 26 at 15:55






            • 2




              @EmilyL. But lambdas are preferred over std::bind! There is no need for it now. Lambdas are far more expressive.
              – Lightness Races in Orbit
              Dec 27 at 2:33










            • @lightnessracesinorbit that's the first I've heard, can you give a reference? I still feel like bind is better expressing the intent
              – Emily L.
              Dec 27 at 12:24






            • 2




              @EmilyL. Sure! stackoverflow.com/a/17545183/560648
              – Lightness Races in Orbit
              Dec 27 at 14:02
















            4














            In general your code looks good. But I have some little annotations (improvements) for you.



            1. I'd prefer direct initialization of itr for sake of readability:



            myMapType::const_iterator itr = myMap.find(2);


            instead of



            myMapType::const_iterator itr;
            itr = myMap.find(2);


            That said you could also avoid



            typedef std::map<int, runFunc> myMapType;


            completely using the auto keyword:



            auto itr = myMap.find(2);


            2. Make use std::function and lambda bindings



            For the callable value parameter of the std::map I'd prefer to use an appropriate std::function value type and lambda function bindings to the instance to operate on.



            testClass t1;

            std::map<int, std::function<void()>> myMap;
            myMap.emplace(1, [&t1](){t1.testFunc1();});
            myMap.emplace(2, [&t1](){t1.testFunc2();});


            This will give you greater flexibility for later changes and use of other classes than just testClass. Also you can get rid of that other type definition then:



            typedef void(testClass::*runFunc)(void);


            As soon you want to use your map for the general case you can clearly see the benefits:



            class A {
            public:
            void print() { std::cout << "print() from class A.n"; }
            };

            class B {
            public:
            void print() { std::cout << "print() from class B.n"; }
            };

            // ...
            int main() {
            A a;
            B b;

            std::map<int, std::function<void()>> myMap;
            myMap.emplace(1, [&a](){a.print();});
            myMap.emplace(2, [&b](){b.print();});

            }




            Here's my set of changes in whole (you can check it's still working as intended here):



            #include <map>
            #include <string>
            #include <iostream>
            #include <functional>

            class testClass
            {
            public:
            void testFunc1() { std::cout << "func1n"; }
            void testFunc2() { std::cout << "func2n"; }
            };

            int main() {
            testClass t1;

            std::map<int, std::function<void()>> myMap;
            myMap.emplace(1, [&t1](){t1.testFunc1();});
            myMap.emplace(2, [&t1](){t1.testFunc2();});

            auto itr = myMap.find(2);

            if (itr != myMap.end()) {
            (itr->second)();
            }
            }





            share|improve this answer























            • Instead of a lambda that calls the function you can use std::bind.
              – Emily L.
              Dec 26 at 15:55






            • 2




              @EmilyL. But lambdas are preferred over std::bind! There is no need for it now. Lambdas are far more expressive.
              – Lightness Races in Orbit
              Dec 27 at 2:33










            • @lightnessracesinorbit that's the first I've heard, can you give a reference? I still feel like bind is better expressing the intent
              – Emily L.
              Dec 27 at 12:24






            • 2




              @EmilyL. Sure! stackoverflow.com/a/17545183/560648
              – Lightness Races in Orbit
              Dec 27 at 14:02














            4












            4








            4






            In general your code looks good. But I have some little annotations (improvements) for you.



            1. I'd prefer direct initialization of itr for sake of readability:



            myMapType::const_iterator itr = myMap.find(2);


            instead of



            myMapType::const_iterator itr;
            itr = myMap.find(2);


            That said you could also avoid



            typedef std::map<int, runFunc> myMapType;


            completely using the auto keyword:



            auto itr = myMap.find(2);


            2. Make use std::function and lambda bindings



            For the callable value parameter of the std::map I'd prefer to use an appropriate std::function value type and lambda function bindings to the instance to operate on.



            testClass t1;

            std::map<int, std::function<void()>> myMap;
            myMap.emplace(1, [&t1](){t1.testFunc1();});
            myMap.emplace(2, [&t1](){t1.testFunc2();});


            This will give you greater flexibility for later changes and use of other classes than just testClass. Also you can get rid of that other type definition then:



            typedef void(testClass::*runFunc)(void);


            As soon you want to use your map for the general case you can clearly see the benefits:



            class A {
            public:
            void print() { std::cout << "print() from class A.n"; }
            };

            class B {
            public:
            void print() { std::cout << "print() from class B.n"; }
            };

            // ...
            int main() {
            A a;
            B b;

            std::map<int, std::function<void()>> myMap;
            myMap.emplace(1, [&a](){a.print();});
            myMap.emplace(2, [&b](){b.print();});

            }




            Here's my set of changes in whole (you can check it's still working as intended here):



            #include <map>
            #include <string>
            #include <iostream>
            #include <functional>

            class testClass
            {
            public:
            void testFunc1() { std::cout << "func1n"; }
            void testFunc2() { std::cout << "func2n"; }
            };

            int main() {
            testClass t1;

            std::map<int, std::function<void()>> myMap;
            myMap.emplace(1, [&t1](){t1.testFunc1();});
            myMap.emplace(2, [&t1](){t1.testFunc2();});

            auto itr = myMap.find(2);

            if (itr != myMap.end()) {
            (itr->second)();
            }
            }





            share|improve this answer














            In general your code looks good. But I have some little annotations (improvements) for you.



            1. I'd prefer direct initialization of itr for sake of readability:



            myMapType::const_iterator itr = myMap.find(2);


            instead of



            myMapType::const_iterator itr;
            itr = myMap.find(2);


            That said you could also avoid



            typedef std::map<int, runFunc> myMapType;


            completely using the auto keyword:



            auto itr = myMap.find(2);


            2. Make use std::function and lambda bindings



            For the callable value parameter of the std::map I'd prefer to use an appropriate std::function value type and lambda function bindings to the instance to operate on.



            testClass t1;

            std::map<int, std::function<void()>> myMap;
            myMap.emplace(1, [&t1](){t1.testFunc1();});
            myMap.emplace(2, [&t1](){t1.testFunc2();});


            This will give you greater flexibility for later changes and use of other classes than just testClass. Also you can get rid of that other type definition then:



            typedef void(testClass::*runFunc)(void);


            As soon you want to use your map for the general case you can clearly see the benefits:



            class A {
            public:
            void print() { std::cout << "print() from class A.n"; }
            };

            class B {
            public:
            void print() { std::cout << "print() from class B.n"; }
            };

            // ...
            int main() {
            A a;
            B b;

            std::map<int, std::function<void()>> myMap;
            myMap.emplace(1, [&a](){a.print();});
            myMap.emplace(2, [&b](){b.print();});

            }




            Here's my set of changes in whole (you can check it's still working as intended here):



            #include <map>
            #include <string>
            #include <iostream>
            #include <functional>

            class testClass
            {
            public:
            void testFunc1() { std::cout << "func1n"; }
            void testFunc2() { std::cout << "func2n"; }
            };

            int main() {
            testClass t1;

            std::map<int, std::function<void()>> myMap;
            myMap.emplace(1, [&t1](){t1.testFunc1();});
            myMap.emplace(2, [&t1](){t1.testFunc2();});

            auto itr = myMap.find(2);

            if (itr != myMap.end()) {
            (itr->second)();
            }
            }






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Dec 26 at 15:05

























            answered Dec 26 at 14:02









            πάντα ῥεῖ

            3,91531328




            3,91531328












            • Instead of a lambda that calls the function you can use std::bind.
              – Emily L.
              Dec 26 at 15:55






            • 2




              @EmilyL. But lambdas are preferred over std::bind! There is no need for it now. Lambdas are far more expressive.
              – Lightness Races in Orbit
              Dec 27 at 2:33










            • @lightnessracesinorbit that's the first I've heard, can you give a reference? I still feel like bind is better expressing the intent
              – Emily L.
              Dec 27 at 12:24






            • 2




              @EmilyL. Sure! stackoverflow.com/a/17545183/560648
              – Lightness Races in Orbit
              Dec 27 at 14:02


















            • Instead of a lambda that calls the function you can use std::bind.
              – Emily L.
              Dec 26 at 15:55






            • 2




              @EmilyL. But lambdas are preferred over std::bind! There is no need for it now. Lambdas are far more expressive.
              – Lightness Races in Orbit
              Dec 27 at 2:33










            • @lightnessracesinorbit that's the first I've heard, can you give a reference? I still feel like bind is better expressing the intent
              – Emily L.
              Dec 27 at 12:24






            • 2




              @EmilyL. Sure! stackoverflow.com/a/17545183/560648
              – Lightness Races in Orbit
              Dec 27 at 14:02
















            Instead of a lambda that calls the function you can use std::bind.
            – Emily L.
            Dec 26 at 15:55




            Instead of a lambda that calls the function you can use std::bind.
            – Emily L.
            Dec 26 at 15:55




            2




            2




            @EmilyL. But lambdas are preferred over std::bind! There is no need for it now. Lambdas are far more expressive.
            – Lightness Races in Orbit
            Dec 27 at 2:33




            @EmilyL. But lambdas are preferred over std::bind! There is no need for it now. Lambdas are far more expressive.
            – Lightness Races in Orbit
            Dec 27 at 2:33












            @lightnessracesinorbit that's the first I've heard, can you give a reference? I still feel like bind is better expressing the intent
            – Emily L.
            Dec 27 at 12:24




            @lightnessracesinorbit that's the first I've heard, can you give a reference? I still feel like bind is better expressing the intent
            – Emily L.
            Dec 27 at 12:24




            2




            2




            @EmilyL. Sure! stackoverflow.com/a/17545183/560648
            – Lightness Races in Orbit
            Dec 27 at 14:02




            @EmilyL. Sure! stackoverflow.com/a/17545183/560648
            – Lightness Races in Orbit
            Dec 27 at 14:02











            0














            Given your current test code, there's no reason for testClass to exist. Your two test functions can simply be functions in the global namespace, and then your emplace calls can be simplified.



            void testFunc1() { std::cout << "func1n"; }
            void testFunc2() { std::cout << "func2n"; }

            typedef void(*runFunc)(void);
            // ...

            myMap.emplace(1, testFunc1);
            myMap.emplace(2, testFunc2);





            share|improve this answer





















            • thanks for your suggestion. my code above is a simplified version of what I really have to do. with just global functions it won't go.
              – Gasper J.
              Dec 26 at 18:40










            • See comments on question, in that case. This is off-topic.
              – Reinderien
              Dec 26 at 21:52
















            0














            Given your current test code, there's no reason for testClass to exist. Your two test functions can simply be functions in the global namespace, and then your emplace calls can be simplified.



            void testFunc1() { std::cout << "func1n"; }
            void testFunc2() { std::cout << "func2n"; }

            typedef void(*runFunc)(void);
            // ...

            myMap.emplace(1, testFunc1);
            myMap.emplace(2, testFunc2);





            share|improve this answer





















            • thanks for your suggestion. my code above is a simplified version of what I really have to do. with just global functions it won't go.
              – Gasper J.
              Dec 26 at 18:40










            • See comments on question, in that case. This is off-topic.
              – Reinderien
              Dec 26 at 21:52














            0












            0








            0






            Given your current test code, there's no reason for testClass to exist. Your two test functions can simply be functions in the global namespace, and then your emplace calls can be simplified.



            void testFunc1() { std::cout << "func1n"; }
            void testFunc2() { std::cout << "func2n"; }

            typedef void(*runFunc)(void);
            // ...

            myMap.emplace(1, testFunc1);
            myMap.emplace(2, testFunc2);





            share|improve this answer












            Given your current test code, there's no reason for testClass to exist. Your two test functions can simply be functions in the global namespace, and then your emplace calls can be simplified.



            void testFunc1() { std::cout << "func1n"; }
            void testFunc2() { std::cout << "func2n"; }

            typedef void(*runFunc)(void);
            // ...

            myMap.emplace(1, testFunc1);
            myMap.emplace(2, testFunc2);






            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Dec 26 at 17:54









            Reinderien

            3,299720




            3,299720












            • thanks for your suggestion. my code above is a simplified version of what I really have to do. with just global functions it won't go.
              – Gasper J.
              Dec 26 at 18:40










            • See comments on question, in that case. This is off-topic.
              – Reinderien
              Dec 26 at 21:52


















            • thanks for your suggestion. my code above is a simplified version of what I really have to do. with just global functions it won't go.
              – Gasper J.
              Dec 26 at 18:40










            • See comments on question, in that case. This is off-topic.
              – Reinderien
              Dec 26 at 21:52
















            thanks for your suggestion. my code above is a simplified version of what I really have to do. with just global functions it won't go.
            – Gasper J.
            Dec 26 at 18:40




            thanks for your suggestion. my code above is a simplified version of what I really have to do. with just global functions it won't go.
            – Gasper J.
            Dec 26 at 18:40












            See comments on question, in that case. This is off-topic.
            – Reinderien
            Dec 26 at 21:52




            See comments on question, in that case. This is off-topic.
            – Reinderien
            Dec 26 at 21:52










            Gasper J. is a new contributor. Be nice, and check out our Code of Conduct.










            draft saved

            draft discarded


















            Gasper J. is a new contributor. Be nice, and check out our Code of Conduct.













            Gasper J. is a new contributor. Be nice, and check out our Code of Conduct.












            Gasper J. is a new contributor. Be nice, and check out our Code of Conduct.
















            Thanks for contributing an answer to Code Review Stack Exchange!


            • 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.


            Use MathJax to format equations. MathJax reference.


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





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • 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%2fcodereview.stackexchange.com%2fquestions%2f210356%2fimprovement-for-stdmap-int-run-some-function-double-dispatch%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

            Сан-Квентин

            8-я гвардейская общевойсковая армия

            Алькесар