Trying & failing to make a function that returns functions... (C++11)

Discussion in 'C++' started by Mark, Mar 9, 2012.

  1. Mark

    Mark Guest

    Hi,

    I am trying to make a function that will create and return another
    function (a closure that captures some state).

    Here's the usage I want:

    std::vector<std::string> on_off{"on", "off"};
    StringValidatorFunction on_off_validator =
    make_string_set_validator(on_off.begin(), on_off.end());
    auto s = on_off_validator("on"); // s == "on"
    auto t = on_off_validator("awf"); // throws
    std::vector<std::string> color{"red", "green", "blue"};
    StringValidatorFunction color_validator =
    make_string_set_validator(color.begin(), color.end());
    auto r = color_validator("red"); // s == "red"
    auto y = color_validator("yellow"); // throws

    Here's what I've got so far:

    using StringValidatorFunction = std::function<std::string(const
    std::string&)>;

    template <class Iter>
    StringValidatorFunction make_string_set_validator(const Iter first,
    const Iter end)
    {
    std::unordered_set<std::string> valid_strings;
    std::for_each(first.begin(), first.end(),
    [&valid_strings](const std::string &s)
    {valid_strings.insert(s);});
    return [valid_strings](const std::string &s)->std::string{
    if (valid_strings.find(s) == valid_strings.end())
    throw ValueError("Invalid string '" + s + "'");
    return s;
    };
    }

    This is the first time I've tried to use lambdas (I'm just starting
    out with C++11), and GCC 4.7.0 isn't helpful (at least not to me):

    main.o: In function `main':
    main.cpp:(.text+0x253): undefined reference to
    `std::function<std::string ()(std::string const&)>
    make_string_set_validator<__gnu_cxx::__normal_iterator<std::string*,
    std::vector<std::string, std::allocator<std::string> > >
    >(__gnu_cxx::__normal_iterator<std::string*, std::vector<std::string,

    std::allocator<std::string> > >,
    __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string,
    std::allocator<std::string> > >)'
    collect2: error: ld returned 1 exit status

    Any suggestions welcome:)

    Thanks!
     
    Mark, Mar 9, 2012
    #1
    1. Advertising

  2. Mark

    Mark Guest

    On Mar 9, 11:34 am, Mark <> wrote:
    > Hi,
    >
    > I am trying to make a function that will create and return another
    > function (a closure that captures some state).

    [snip]

    I'd made the silly mistake of putting the templated function in the
    source rather than the header:-(

    And realized that there's a slightly nicer usage possible:

    std::vector<std::string> on_off{"on", "off"};
    auto on_off_validator = make_string_set_validator(on_off);

    Using:

    template <class T>
    StringValidatorFunction make_string_set_validator(const T
    &valid_strings)
    {
    std::unordered_set<std::string> strings;
    std::for_each(std::begin(valid_strings), std::end(valid_strings),
    [&strings](const std::string &s){strings.insert(s);});
    return [strings](const std::string &s)->std::string{
    if (strings.find(s) == strings.end())
    throw ValueError("Invalid string '" + s + "'");
    return s;
    };
    }
     
    Mark, Mar 9, 2012
    #2
    1. Advertising

  3. Mark <> wrote:
    > I'd made the silly mistake of putting the templated function in the
    > source rather than the header:-(


    In principle there's nothing wrong with that, as long as you somehow
    end up instantiating the template implementation will all the types with
    which it's used in the program. Of course usually the easiest way to do
    that is to put the implementation in the header where it's declared.

    (It is, in fact, possible to simply declare (rather than define) a
    template in a header, use only this declaration in the different
    compilation units, and put the implementation of the template in one
    single compilation unit where it's explicitly instantiated for each
    used type. (C++ support a special syntax for explicit template
    instantiation.) This is akin to the (now defunct) export template
    mechanism, except that you have to do the instantiation manually, which
    makes it infeasible in most practical cases.)
     
    Juha Nieminen, Mar 9, 2012
    #3
  4. Mark

    BGB Guest

    Re: Trying & failing to make a function that returns functions...(C++11)

    On 3/9/2012 4:54 AM, Mark wrote:
    > On Mar 9, 11:34 am, Mark<> wrote:
    >> Hi,
    >>
    >> I am trying to make a function that will create and return another
    >> function (a closure that captures some state).

    > [snip]
    >
    > I'd made the silly mistake of putting the templated function in the
    > source rather than the header:-(
    >



    <snip, example>

    although I am not really experienced with C++11 nor do I have an easy
    time following the code, it does look a little worrying:
    as I understand it, returning (C++11) closures in this way may not be safe?

    the issue is mostly where the space for any captured references is
    stored, and if it is copied along with the closure, or is somewhere
    "stable" (such as in the heap) vs somewhere unstable (say, on the stack).

    non-capturing lambdas are known safe (and may also be cast to function
    pointers);
    lamdas which capturing references to locals are known unsafe (to return);
    what about capturing values or references to data outside the parent frame?

    (both safe and unsafe implementations can be easily imagined, but does
    the standard mandate this case is safe? I don't actually know...).



    ironically (OT / side-note):
    my script VM doesn't have these issues (with closures), at the cost that
    everything is heap allocated (they can also be coerced into C-style
    function pointers as well). the tradeoff though is that they either have
    to be deleted/freed, or risk triggering the GC to do its thing (say, if
    closures are created in large numbers and/or at a rapid pace).

    technically, they are "executable objects", allocated in RWX
    (Read/Write/Execute) memory, with executable code (a "trampoline")
    preceding any data members (so, one is essentially jumping into/through
    a struct). sadly, they also have to be "locked"/"pinned" before they can
    be safely used as callbacks (if stored in non-GC'ed memory), which
    prevents them from being automatically GC'ed (allowing for a potentially
    VM breaking edge case).


    or such...
     
    BGB, Mar 9, 2012
    #4
  5. BGB <> wrote:
    > what about capturing values or references to data outside the parent frame?


    A lambda that captures by value is safe to outlive the scope of those
    values. The captured objects are copied to a local stack of the lambda,
    which lives for as long as the lambda itself. (How this is actually
    implemented internally probably depends on the compiler.)
     
    Juha Nieminen, Mar 9, 2012
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    4
    Views:
    377
    Larry Smith
    Apr 2, 2007
  2. Replies:
    3
    Views:
    2,423
    Microsoft Newsserver
    Mar 25, 2008
  3. nathan

    ws failing trying to load jdolbhfc.dll

    nathan, Oct 1, 2003, in forum: ASP .Net Web Services
    Replies:
    0
    Views:
    97
    nathan
    Oct 1, 2003
  4. dougal.s
    Replies:
    2
    Views:
    101
    dougal.s
    Oct 3, 2006
  5. Brian Candler
    Replies:
    2
    Views:
    121
    Brian Candler
    Apr 11, 2008
Loading...

Share This Page