Home > Software design >  Writing Lambda signatures for lazy initialization
Writing Lambda signatures for lazy initialization

Time:01-14

#include <iostream>
#include <string>

typedef std::string S;

template <typename T>
static inline T* getOrCreate( ( []() -> auto) creationSpren *) {
    bool assigned = false;

    if (!assigned) {
        // invoke creationSpren with passed arguments 
        // assign
    }
}

int main()
{
    auto& xx = []() {
        return new std::string("abc");
    };

    auto& zzz = getOrCreate<S>(xx);
}

note: this code does not compile, that is the problem I am trying to solve.

however, I wrote this minimum example to illustrate the problem, it is as barebones as possible.

What I'm trying to achieve is simple, to use lambdas to achieve lazy initialization of an object, when it is needed (i.e. when a retrieve fails, it calls the lambda and assigns the object (i.e. stores it) and returns it)

What I have problems with, as I have no experience with lambdas is both the signatures.

That is what I am asking, how to write the 2 lambda signatures. thanks.

and yes, it needs to be templated.

verbatim errors

<source>: In lambda function:
<source>:7:45: error: expected '{' before ')' token
    7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) {
      |                                             ^
<source>: At global scope:
<source>:7:46: error: expected ')' before 'creationSpren'
    7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) {
      |                             ~                ^~~~~~~~~~~~~~
      |                                              )
<source>:7:63: error: expected ';' before '{' token
    7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) {
      |                                                               ^~
      |                                                               ;
<source>: In function 'int main()':
<source>:18:16: error: cannot bind non-const lvalue reference of type 'main()::<lambda()>&' to an rvalue of type 'main()::<lambda()>'
   18 |     auto& xx = []() {
      |                ^~~~~~
   19 |         return new std::string("abc");
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   20 |     };
      |     ~           
<source>: In instantiation of 'std::__cxx11::basic_string<char>* getOrCreate<std::__cxx11::basic_string<char> >':
<source>:22:17:   required from here
<source>:7:33: error: cannot convert '<lambda()>' to 'std::__cxx11::basic_string<char>*' in initialization
    7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) {
      |                                 ^~~~~~~~~~~~
      |                                 |
      |                                 <lambda()>
<source>:22:31: error: 'getOrCreate<std::__cxx11::basic_string<char> >' cannot be used as a function
   22 |     auto& zzz = getOrCreate<S>(xx);
      |                 ~~~~~~~~~~~~~~^~~~
ASM generation compiler returned: 1
<source>: In lambda function:
<source>:7:45: error: expected '{' before ')' token
    7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) {
      |                                             ^
<source>: At global scope:
<source>:7:46: error: expected ')' before 'creationSpren'
    7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) {
      |                             ~                ^~~~~~~~~~~~~~
      |                                              )
<source>:7:63: error: expected ';' before '{' token
    7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) {
      |                                                               ^~
      |                                                               ;
<source>: In function 'int main()':
<source>:18:16: error: cannot bind non-const lvalue reference of type 'main()::<lambda()>&' to an rvalue of type 'main()::<lambda()>'
   18 |     auto& xx = []() {
      |                ^~~~~~
   19 |         return new std::string("abc");
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   20 |     };
      |     ~           
<source>: In instantiation of 'std::__cxx11::basic_string<char>* getOrCreate<std::__cxx11::basic_string<char> >':
<source>:22:17:   required from here
<source>:7:33: error: cannot convert '<lambda()>' to 'std::__cxx11::basic_string<char>*' in initialization
    7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) {
      |                                 ^~~~~~~~~~~~
      |                                 |
      |                                 <lambda()>
<source>:22:31: error: 'getOrCreate<std::__cxx11::basic_string<char> >' cannot be used as a function
   22 |     auto& zzz = getOrCreate<S>(xx);
      |                 ~~~~~~~~~~~~~~^~~~
Execution build compiler returned: 1

CodePudding user response:

If you look at the standard library and their functions which takes a callable object, it uses templates.

I recommend that for your function as well:

template<typename T, typename F>
static inline T* getOrCreate(F creationSpren)
{
    // ...
}

There's another problem with your current function: The variable assigned is a normal local variable. It will be created and initialized to false each time getOrCreate is called.

You need to make it a static local variable.

CodePudding user response:

what you have now is just a complicated version of static local variable. (usually used in singleton)

int main(){
    auto xx = []{
        static std::string* v = new std::string("abc");
        return v;
    };

    std::string* a = xx();
    std::string* b = xx();
    assert(a==b);

    delete a; // manually cleanup as you `new` it
}

https://godbolt.org/z/GnsGaqnx3

  • Related