Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Trying & failing to make a function that returns functions... (C++11)

Reply
Thread Tools

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

 
 
Mark
Guest
Posts: n/a
 
      03-09-2012
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_iter ator<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!
 
Reply With Quote
 
 
 
 
Mark
Guest
Posts: n/a
 
      03-09-2012
On Mar 9, 11:34*am, Mark <(E-Mail Removed)> 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;
};
}


 
Reply With Quote
 
 
 
 
Juha Nieminen
Guest
Posts: n/a
 
      03-09-2012
Mark <(E-Mail Removed)> 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.)
 
Reply With Quote
 
BGB
Guest
Posts: n/a
 
      03-09-2012
On 3/9/2012 4:54 AM, Mark wrote:
> On Mar 9, 11:34 am, Mark<(E-Mail Removed)> 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...
 
Reply With Quote
 
Juha Nieminen
Guest
Posts: n/a
 
      03-09-2012
BGB <(E-Mail Removed)> 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.)
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
problem in running a basic code in python 3.3.0 that includes HTML file Satabdi Mukherjee Python 1 04-04-2013 07:48 PM
Trying and failing to disable button in javascript teddysnips@hotmail.com ASP .Net 3 03-25-2008 09:00 AM
Trying to use KSystemTray - and failing jk@pusspaws.net C++ 4 04-02-2007 02:43 AM
Trying (and failing) at setting up a wireless adhoc connection Adnan Computer Support 2 05-08-2006 06:05 PM
ws failing trying to load jdolbhfc.dll nathan ASP .Net Web Services 0 10-01-2003 05:14 PM



Advertisments