c++ 为惰性初始化编写Lambda签名

suzh9iv8  于 2023-01-14  发布在  其他
关注(0)|答案(2)|浏览(139)
#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);
}

注意:这段代码不能编译,这是我要解决的问题。
然而,我写了这个最小的例子来说明这个问题,它尽可能的简单。
我尝试实现的很简单,就是使用lambda来实现对象的惰性初始化,当需要的时候(即当检索失败时,它调用lambda并分配对象(即存储它)并返回它)
我有什么问题,因为我没有经验与lambdas是这两个签名。
这就是我要问的,如何写2个lambda签名。谢谢。
是的,它需要模板。

逐字错误

<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
yjghlzjz

yjghlzjz1#

如果你看一下标准库和它们接受可调用对象的函数,它使用 templates
我建议您也这样做:

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

您当前的函数还有另一个问题:变量assigned是一个普通的局部变量,每次调用getOrCreate时都会创建并初始化为false
您需要将其设置为static局部变量。
如果需要将参数传递给getOrCreate,然后将其转发给creationSpren函数,则使用 * 模板参数包 *:

#include <utility>
#include <iostream>

template<typename T, typename F, typename ...A>
static inline T* getOrCreate(F creationSpren, A&& ...args)
{
    creationSpren(std::forward<A>(args)...);
    return nullptr;
}

int main()
{
    auto lambda_noargs = []() { std::cout << "No arguments\n"; };
    auto lambda_twoargs = [](int, int) { std::cout << "Two arguments\n"; };

    getOrCreate<int>(lambda_noargs);
    getOrCreate<int>(lambda_twoargs, 1, 2);
}
o0lyfsai

o0lyfsai2#

你现在所拥有的只是一个复杂的静态局部变量。(通常用于单例)

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

相关问题