无法从<大括号包围的初始化列表>转换为std::map

huangapple go评论71阅读模式
英文:

Could not convert from <brace-enclosed initializer list> to std::map

问题

以下是您要翻译的内容:

I am stuck on a problem and I know that some similar questions have already been posted here, but I have not been able to solve the problem yet based on their answers. Could someone please help me with this?

I have the following class in a .h file:

class A
{
private:

    struct ARGS
    {
        size_t length{0};
        std::string str{""};
    };

    typedef int(A::*FUNCPTR)(const std::vector<ARGS> &);
    std::map<const std::string, FUNCPTR> func_map
    {
        {"PRINT_HW",
          [this](const std::vector<ARGS> args){
            validate(args, 0);
            A::cmd_phw();
          }
        },
        {"PRINT_NAME",
          [this](const std::vector<ARGS> args){
            validate(args, 1);
            A::cmd_pn(args[0]);
          }
        },
        {"PRINT_NAME_SURNAME",
          [this](const std::vector<ARGS> args){
            validate(args, 2);
            A::cmd_pns(args[0], args[1]);
          }
        },
    };

    // function declaration for the existing commands.
    int cmd_phw();
    int cmd_pn(ARGS args1);
    int cmd_pns(ARGS args1, ARGS args2);

    static void validate(const std::vector<ARGS> &args, size_t needed)
    {
        if (args.size() != needed)
        {
            throw std::invalid_argument("Wrong number of arguments!");
        }
    }

public:
    A(); // Class constructor declaration
    int call_print(const std::string& str, const std::vector<ARGS> &args);
};

And in the .cpp file I have all the definitions, including the call_print as follows:

int A::call_print(const std::string& str, const std::vector<ARGS> &args)
{
  FUNCPTR fp = func_map[str];
  int r = (this->*fp)(args);

  return r;
}

But unfortunatelly it results in an error:

could not convert ‘{{"PRINT_HW", <lambda closure object>A::<lambda(std::vector<A::ARGS>)>{((A*)this)}}, {"PRINT_NAME", <lambda closure object>A::<lambda(std::vector<A::ARGS>)>{((A*)this)}}, {"PRINT_NAME_SURNAME", <lambda closure object>A::<lambda(std::vector<A::ARGS>)>{((A*)this)}}}’ from ‘<brace-enclosed initializer list>’ to ‘std::map<const std::__cxx11::basic_string<char>, int (A::*)(const std::vector<A::ARGS>&)>’

<details>
<summary>英文:</summary>

I am stuck on a problem and I know that some similar questions have already been posted here, but I have not been able to solve the problem yet based on their answers. Could someone please help me with this?

I have the following class in a .h file: 

class A
{
private:

struct ARGS
{
    size_t length{0};
    std::string str{&quot;&quot;};
};

typedef int(A::*FUNCPTR)(const std::vector&lt;ARGS&gt; &amp;); 
std::map&lt;const std::string, FUNCPTR&gt; func_map
{    
    {&quot;PRINT_HW&quot;,
      [this](const std::vector&lt;ARGS&gt; args){
        validate(args, 0);
        A::cmd_phw();
      }
    },
    {&quot;PRINT_NAME&quot;,
      [this](const std::vector&lt;ARGS&gt; args){
        validate(args, 1);
        A::cmd_pn(args[0]);
      }
    },
    {&quot;PRINT_NAME_SURNAME&quot;,
      [this](const std::vector&lt;ARGS&gt; args){
        validate(args, 2);
        A::cmd_pns(args[0], args[1]);
      }
    },
};

// function declaration for the existing commands. 
int cmd_phw();
int cmd_pn(ARGS args1);
int cmd_pns(ARGS args1, ARGS args2);

static void validate(const std::vector&lt;ARGS&gt; &amp;args, size_t needed)
{
    if (args.size() != needed)
    {
        throw std::invalid_argument(&quot;Wrong number of arguments!&quot;);
    }
}    

public:
A(); // Class constructor declaration
int call_print(const std::string& str, const std::vector<ARGS> &args);
};

And in the .cpp file I have all the definitions, including the `call_print` as follows:

int A::call_print(const std::string& str, const std::vector<ARGS> &args)
{
FUNCPTR fp = func_map[str];
int r = (this->*fp)(args);

return r;
}


But unfortunatelly it results in an error: 

could not convert ‘{{"PRINT_HW", <lambda closure object>A::<lambda(std::vector<A::ARGS>)>{((A*)this)}}, {"PRINT_NAME", <lambda closure object>A::<lambda(std::vector<A::ARGS>)>{((A*)this)}}, {"PRINT_NAME_SURNAME", <lambda closure object>A::<lambda(std::vector<A::ARGS>)>{((A*)this)}}}’ from ‘<brace-enclosed initializer list>’ to ‘std::map<const std::__cxx11::basic_string<char>, int (A::*)(const std::vector<A::ARGS>&)>’


</details>


# 答案1
**得分**: 1

无法将lambda表达式转换为成员函数指针。Lambda表达式只能转换为普通的函数指针,但前提是它是*非捕获*的。

由于您想使用*捕获*的lambda表达式,您需要将`std::function`用作您的`std::map`值类型,例如:

```cpp
class A 
{
public:
    struct ARG
    {
        size_t length{0};
        std::string str{""};
    };

    using ARGS = std::vector<ARG>;

private:    
    using FUNCPTR = std::function<int(const ARGS&)>;
    std::map<std::string, FUNCPTR> func_map
    {    
        {"PRINT_HW",
          [this](const ARGS& args) -> int {
            A::validate(args, 0);
            return cmd_phw();
          }
        },
        {"PRINT_NAME",
          [this](const ARGS& args) -> int {
            A::validate(args, 1);
            return cmd_pn(args[0]);
          }
        },
        {"PRINT_NAME_SURNAME",
          [this](const ARGS& args) -> int {
            A::validate(args, 2);
            return cmd_pns(args[0], args[1]);
          }
        },
    };

    // 现有命令的函数声明。
    int cmd_phw();
    int cmd_pn(const ARG& args1);
    int cmd_pns(const ARG& args1, const ARG& args2);
 
    static void validate(const ARGS &args, size_t needed)
    {
        if (args.size() != needed)
        {
            throw std::invalid_argument("参数数量错误!");
        }
    }    

public:
    A(); // 类构造函数声明
    int call_print(const std::string& str, const ARGS &args);
};
int A::call_print(const std::string& str, const ARGS &args)
{
  return func_map.at(str)(args);
}
英文:

You can't convert a lambda into a pointer-to-member-function. A lambda can be converted into a plain pointer-to-function, but only if it is non-capturing.

Since you want to use capturing lambdas, you will have to use std::function instead as your std::map value type, eg:

class A 
{
public:
    struct ARG
    {
        size_t length{0};
        std::string str{&quot;&quot;};
    };

    using ARGS = std::vector&lt;ARG&gt;;

private:    
    using FUNCPTR = std::function&lt;int(const ARGS&amp;)&gt;;
    std::map&lt;std::string, FUNCPTR&gt; func_map
    {    
        {&quot;PRINT_HW&quot;,
          [this](const ARGS&amp; args) -&gt; int {
            A::validate(args, 0);
            return cmd_phw();
          }
        },
        {&quot;PRINT_NAME&quot;,
          [this](const ARGS&amp; args) -&gt; int {
            A::validate(args, 1);
            return cmd_pn(args[0]);
          }
        },
        {&quot;PRINT_NAME_SURNAME&quot;,
          [this](const ARGS&amp; args) -&gt; int {
            A::validate(args, 2);
            return cmd_pns(args[0], args[1]);
          }
        },
    };

    // function declaration for the existing commands. 
    int cmd_phw();
    int cmd_pn(const ARG&amp; args1);
    int cmd_pns(const ARG&amp; args1, const ARG&amp; args2);
 
    static void validate(const ARGS &amp;args, size_t needed)
    {
        if (args.size() != needed)
        {
            throw std::invalid_argument(&quot;Wrong number of arguments!&quot;);
        }
    }    

public:
    A(); // Class constructor declaration
    int call_print(const std::string&amp; str, const ARGS &amp;args);
};
int A::call_print(const std::string&amp; str, const ARGS &amp;args)
{
  return func_map.at(str)(args);
}

答案2

得分: -2

错误消息表明,传递给std::map构造函数的初始化列表的类型与地图的value_type的类型不兼容。具体来说,地图的value_typeint (A::*)(const std::vector&lt;ARGS&gt;&amp;),它是一个成员函数指针类型,而初始化列表提供了具有不同类型的lambda函数。

要修复此错误,您需要确保lambda函数与成员函数指针具有相同的类型。一种方法是使用与成员函数相同签名的lambda函数,如下所示:

{
    {"PRINT_HW", &A::cmd_phw},
    {"PRINT_NAME", &A::cmd_pn},
    {"PRINT_NAME_SURNAME", &A::cmd_pns}
}

或者,您可以为lambda函数定义一个具有正确签名的类型别名,并在地图声明中使用它,如下所示:

using FUNCPTR = int(A::*)(const std::vector&lt;ARGS&gt;&amp;);
using LambdaType = std::function&lt;int(A*, const std::vector&lt;ARGS&gt;&amp;)&gt;;
std::map<std::string, FUNCPTR> func_map {
    {"PRINT_HW", static_cast<FUNCPTR>(&A::cmd_phw)},
    {"PRINT_NAME", static_cast<FUNCPTR>(&A::cmd_pn)},
    {"PRINT_NAME_SURNAME", static_cast<FUNCPTR>(&A::cmd_pns)}
};

为lambda函数定义一个类型别名LambdaType,具有正确的签名,然后使用static_cast将lambda函数转换为成员函数指针类型FUNCPTR。请注意,在通过指针调用成员函数时,我们还需要将对象的指针(this)作为第一个参数传递。

英文:

The error message suggests that the type of the initializer list passed to the std::map constructor is incompatible with the type of the map's value_type. Specifically, the map's value_type is int (A::*)(const std::vector&lt;ARGS&gt;&amp;), which is a pointer to member function type, while the initializer list provides lambda functions that have a different type.

To fix the error, you need to make sure that the lambda functions have the same type as the pointer to member functions. One way to do this is to define the lambda functions with the same signature as the member functions, like this:

{
    {&quot;PRINT_HW&quot;, &amp;A::cmd_phw},
    {&quot;PRINT_NAME&quot;, &amp;A::cmd_pn},
    {&quot;PRINT_NAME_SURNAME&quot;, &amp;A::cmd_pns}
}

Alternatively, you can define a type alias for the lambda functions with the correct signature and use it in the map declaration, like this:

using FUNCPTR = int(A::*)(const std::vector&lt;ARGS&gt;&amp;);
using LambdaType = std::function&lt;int(A*, const std::vector&lt;ARGS&gt;&amp;)&gt;;
std::map&lt;std::string, FUNCPTR&gt; func_map {
    {&quot;PRINT_HW&quot;, static_cast&lt;FUNCPTR&gt;(&amp;A::cmd_phw)},
    {&quot;PRINT_NAME&quot;, static_cast&lt;FUNCPTR&gt;(&amp;A::cmd_pn)},
    {&quot;PRINT_NAME_SURNAME&quot;, static_cast&lt;FUNCPTR&gt;(&amp;A::cmd_pns)}
};

Define a type alias LambdaType for the lambda functions with the correct signature, and then use static_cast to convert the lambdas to the pointer-to-member-function type FUNCPTR. Note that we also need to pass a pointer to the object (this) as the first argument to the member functions when calling them through the pointer.

huangapple
  • 本文由 发表于 2023年4月13日 23:28:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76007252.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定