我不理解为什么我的C++代码出现了错误(不兼容的操作数类型)。

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

I do not understand why error(incompatible operand types) occurred in my c++ code

问题

我用C++编写了一个用于分析JavaScript代码词法单元的代码。以下是相应的函数。为了参考,Kind是一个包含词法单元类型的枚举类,函数toKind的定义在函数analyzeLexeme的下方。

  1. auto analyzeLexeme(std::wstring & source_code) -> std::vector<Token> {
  2. using std::__1::wregex;
  3. using std::regex_search;
  4. using std::vector;
  5. using std::wsmatch;
  6. using std::wstring;
  7. using std::string;
  8. using std::tuple;
  9. using std::map;
  10. wsmatch matched;
  11. Kind result_kind;
  12. map<string, bool> context = { { "in_tmplt", false }, };
  13. auto result = vector<Token>();
  14. auto reSearch = [&source_code, &matched] (const wregex & re) {
  15. return regex_search(source_code, matched, re);
  16. };
  17. source_code += L'\0';
  18. for (; source_code[0]; source_code = matched.suffix()) {
  19. if (reSearch(kReWhiteSpace)) continue;
  20. result.push_back({(
  21. reSearch(kReNumLiteral) ? [] { return Kind::NumberLiteral; } :
  22. reSearch(kReStrLiteral) ? [] { return Kind::StringLiteral; } :
  23. reSearch(kReTmpltHdLiteral) && !context["in_tmplt"] ?
  24. [&] {
  25. context["in_tmplt"] = true;
  26. return Kind::TemplateHeadLiteral;
  27. } :
  28. reSearch(kReTmpltTlLiteral) && context["in_tmplt"] ?
  29. [&] {
  30. context["in_tmplt"] = false;
  31. return Kind::TemplateTailLiteral;
  32. } :
  33. reSearch(kReTmpltMdLiteral) && context["in_tmplt"] ? [] { return Kind::TemplateMiddleLiteral; } :
  34. reSearch(kReTmpltLiteral) ? [] { return Kind::TemplateLiteral; } :
  35. reSearch(kReIdentifierKyword) ? [&] { return toKind(matched.str(), Kind::Identifier); } :
  36. reSearch(kReOperatorBracket) ? [&] { return toKind(matched.str()); } :
  37. [] { return Kind::Unknown; }
  38. )(),
  39. matched.str(),
  40. });
  41. if (result.back().kind == Kind::Unknown) {
  42. std::wcerr << L"[ERR] : Unknown Token : " << source_code.substr(0, 40) << std::endl;
  43. // fwprintf(stderr, L"[ERR] : Unknown Token : %s", source_code.substr(0, 40).c_str());
  44. exit(1);
  45. }
  46. }
  47. return result;
  48. }
  1. // str_to_kind is a map(string to kind).
  2. auto toKind(std::wstring str, Kind default_kind) -> Kind {
  3. return str_to_kind.count(str) ? str_to_kind.at(str) : default_kind;
  4. }

错误出现在这里(reSearch(kReOperatorBracket) ? [&] { return toKind(matched.str()); })。原因是error: incompatible operand types ('(lambda at ~/projects/lexer.cc:69:72)' and '(lambda at ~/projects/lexer.cc:70:17)')

我不明白这个错误的原因,因为toKind的返回类型是Kind,所以lambda函数([&] { return toKind(matched.str()))必须返回Kind值,而lambda函数([] { return Kind::Unknown; })也只能返回Kind类型的值。

起初,我以为是g++无法解释我的代码(在Python中,有时解释器无法解释我不应该写的行)。然而,经过多次尝试,我发现这也不是主要原因。

此外,如果代码被编译,我会使用gdb进行调试,但由于这是编译过程中的问题,我也无法这样做。

英文:

I wrote a code to analyize javascript code lexeme with c++. Below is the corresponding function. For reference, Kind is a enum class that contains kinds of lex, and definition of a function toKind is below of the function analyzeLexeme.

  1. auto analyzeLexeme(std::wstring & source_code) -> std::vector<Token> {
  2. using std::__1::wregex;
  3. using std::regex_search;
  4. using std::vector;
  5. using std::wsmatch;
  6. using std::wstring;
  7. using std::string;
  8. using std::tuple;
  9. using std::map;
  10. wsmatch matched;
  11. Kind result_kind;
  12. map<string, bool> context = { { "in_tmplt", false }, };
  13. auto result = vector<Token>();
  14. auto reSearch = [&source_code, &matched] (const wregex & re) {
  15. return regex_search(source_code, matched, re);
  16. };
  17. source_code += L'\0';
  18. for (; source_code[0]; source_code = matched.suffix()) {
  19. if (reSearch(kReWhiteSpace)) continue;
  20. result.push_back({(
  21. reSearch(kReNumLiteral) ? [] { return Kind::NumberLiteral; } :
  22. reSearch(kReStrLiteral) ? [] { return Kind::StringLiteral; } :
  23. reSearch(kReTmpltHdLiteral) && !context["in_tmplt"] ?
  24. [&] {
  25. context["in_tmplt"] = true;
  26. return Kind::TemplateHeadLiteral;
  27. } :
  28. reSearch(kReTmpltTlLiteral) && context["in_tmplt"] ?
  29. [&] {
  30. context["in_tmplt"] = false;
  31. return Kind::TemplateTailLiteral;
  32. } :
  33. reSearch(kReTmpltMdLiteral) && context["in_tmplt"] ? [] { return Kind::TemplateMiddleLiteral; } :
  34. reSearch(kReTmpltLiteral) ? [] { return Kind::TemplateLiteral; } :
  35. reSearch(kReIdentifierKyword) ? [&] { return toKind(matched.str(), Kind::Identifier); } :
  36. reSearch(kReOperatorBracket) ? [&] { return toKind(matched.str()); } :
  37. [] { return Kind::Unknown; }
  38. )(),
  39. matched.str(),
  40. });
  41. if (result.back().kind == Kind::Unknown) {
  42. std::wcerr << L"[ERR] : Unknown Token : " << source_code.substr(0, 40) << std::endl;
  43. // fwprintf(stderr, L"[ERR] : Unknown Token : %s", source_code.substr(0, 40).c_str());
  44. exit(1);
  45. }
  46. }
  47. return result;
  48. }
  1. // str_to_kind is a map(string to kind).
  2. auto toKind(std::wstring str, Kind default_kind) -> Kind {
  3. return str_to_kind.count(str) ? str_to_kind.at(str) : default_kind;
  4. }

Error is occurred here(reSearch(kReOperatorBracket) ? [&] { return toKind(matched.str()); }). And reason is error: incompatible operand types ('(lambda at ~/projects/lexer.cc:69:72)' and '(lambda at ~/projects/lexer.cc:70:17)').

I do not understand it because return type of toKind is Kind, so lambda function([&] { return toKind(matched.str())) must return Kind value, and lambda function([] { return Kind::Unknown; }) also has no choice but to return a value of type Kind.

At first I thought g++ couldn't interpret my code (in python, sometimes the interpreter can't interpret it if I write down the line I shouldn't write down). However, after many attempts, I found that it was not the main cause either.

Also, if the code was compiled, I would run gdb to debug it, but I couldn't do this either because it was a problem with the compilation process.

答案1

得分: 1

由于您在三元操作中使用了lambda作为操作数,您需要将这些lambda包装在std::function中。

正如您所看到的,所有的lambda都有自己独特的类型,而不是std::function。如果您想要有一个返回一种类型或另一种类型的表达式,您需要某种类型的类型擦除。

考虑以下代码:

  1. std::any test = rand() > 10 ? 42 : "a";

尽管您正在构造一个std::any,但是三元操作符的两个操作数的类型不同,且彼此之间不能转换。

但是以下代码可以正常工作:

  1. std::any test = rand() > 10 ? std::any{42} : std::any{"a"};

然而,您似乎在表达式中立即调用函数。考虑到这一点,您还可以删除所有单语句的lambda,并在三元操作符内部调用多语句。

如果您在现场调用它们,代码将如下所示:

  1. result.push_back({
  2. (
  3. reSearch(kReNumLiteral)
  4. ? Kind::NumberLiteral
  5. : reSearch(kReStrLiteral)
  6. ? Kind::StringLiteral
  7. : reSearch(kReTmpltHdLiteral) && !context["in_tmplt"]
  8. ? [&] {
  9. context["in_tmplt"] = true;
  10. return Kind::TemplateHeadLiteral;
  11. }() // 在这里调用!
  12. : reSearch(kReTmpltTlLiteral) && context["in_tmplt"]
  13. ? [&] {
  14. context["in_tmplt"] = false;
  15. return Kind::TemplateTailLiteral;
  16. }() // 再次在这里调用,lambda被调用。
  17. : reSearch(kReTmpltMdLiteral) && context["in_tmplt"]
  18. ? Kind::TemplateMiddleLiteral
  19. : reSearch(kReTmpltLiteral)
  20. ? Kind::TemplateLiteral;
  21. : reSearch(kReIdentifierKyword)
  22. ? toKind(matched.str(), Kind::Identifier)
  23. : reSearch(kReOperatorBracket)
  24. ? toKind(matched.str())
  25. : Kind::Unknown
  26. ),
  27. matched.str(),
  28. });

如果您将它们全部包装在像std::function这样的类型擦除包装器中,代码将如下所示:

  1. result.push_back({
  2. (
  3. reSearch(kReNumLiteral)
  4. ? std::function{[]{ return Kind::NumberLiteral; }}
  5. : reSearch(kReStrLiteral)
  6. ? std::function{[]{ return Kind::StringLiteral; }}
  7. : reSearch(kReTmpltHdLiteral) && !context["in_tmplt"]
  8. ? std::function{[&] {
  9. context["in_tmplt"] = true;
  10. return Kind::TemplateHeadLiteral;
  11. }}
  12. : reSearch(kReTmpltTlLiteral) && context["in_tmplt"]
  13. ? std::function{[&] {
  14. context["in_tmplt"] = false;
  15. return Kind::TemplateTailLiteral;
  16. }}
  17. : reSearch(kReTmpltMdLiteral) && context["in_tmplt"]
  18. ? std::function{[]{ return Kind::TemplateMiddleLiteral; }}
  19. : reSearch(kReTmpltLiteral)
  20. ? std::function{[]{ return Kind::TemplateLiteral; }}
  21. : reSearch(kReIdentifierKyword)
  22. ? std::function{[]{ return toKind(matched.str(), Kind::Identifier); }}
  23. : reSearch(kReOperatorBracket)
  24. ? std::function{[]{ return toKind(matched.str()); }}
  25. : std::function{[]{ return Kind::Unknown; }}
  26. )(), // 调用包装了lambda的std::function
  27. matched.str(),
  28. });
英文:

Since you use lambdas as operands in a ternary operation, you'll need to wrap those lambdas inside a std::function.

As you can see, all lambdas have their own distinct type that is not std::function. If you want to have an expression that return one type or another, you need some kind of type erasure.

Consider this code:

  1. std::any test = rand() > 10 ? 42 : "a";

Even though you're constructing a std::any, both sides of the operands of the ternary are not the same type and are not convertible between each other.

This code works though:

  1. std::any test = rand() > 10 ? std::any{42} : std::any{"a"};

However, you seems to call the function on the spot, in line in the expression. Considering that, you can also remove all single-statement lambdas, and call the multi statements inside the ternary.

Here's how it would look like if you call them on the spot:

  1. result.push_back({
  2. (
  3. reSearch(kReNumLiteral)
  4. ? Kind::NumberLiteral
  5. : reSearch(kReStrLiteral)
  6. ? Kind::StringLiteral
  7. : reSearch(kReTmpltHdLiteral) && !context["in_tmplt"]
  8. ? [&] {
  9. context["in_tmplt"] = true;
  10. return Kind::TemplateHeadLiteral;
  11. }() // here!
  12. : reSearch(kReTmpltTlLiteral) && context["in_tmplt"]
  13. ? [&] {
  14. context["in_tmplt"] = false;
  15. return Kind::TemplateTailLiteral;
  16. }() // here again, lambda called.
  17. : reSearch(kReTmpltMdLiteral) && context["in_tmplt"]
  18. ? Kind::TemplateMiddleLiteral
  19. : reSearch(kReTmpltLiteral)
  20. ? Kind::TemplateLiteral;
  21. : reSearch(kReIdentifierKyword)
  22. ? toKind(matched.str(), Kind::Identifier)
  23. : reSearch(kReOperatorBracket)
  24. ? toKind(matched.str())
  25. : Kind::Unknown
  26. ),
  27. matched.str(),
  28. });

Here's how it look like if you wrap them all in a type erasure wrapper like std::function:

  1. result.push_back({
  2. (
  3. reSearch(kReNumLiteral)
  4. ? std::function{[]{ return Kind::NumberLiteral; }}
  5. : reSearch(kReStrLiteral)
  6. ? std::function{[]{ return Kind::StringLiteral; }}
  7. : reSearch(kReTmpltHdLiteral) && !context["in_tmplt"]
  8. ? std::function{[&] {
  9. context["in_tmplt"] = true;
  10. return Kind::TemplateHeadLiteral;
  11. }}
  12. : reSearch(kReTmpltTlLiteral) && context["in_tmplt"]
  13. ? std::function{[&] {
  14. context["in_tmplt"] = false;
  15. return Kind::TemplateTailLiteral;
  16. }}
  17. : reSearch(kReTmpltMdLiteral) && context["in_tmplt"]
  18. ? std::function{[]{ return Kind::TemplateMiddleLiteral; }}
  19. : reSearch(kReTmpltLiteral)
  20. ? std::function{[]{ return Kind::TemplateLiteral; }}
  21. : reSearch(kReIdentifierKyword)
  22. ? std::function{[]{ return toKind(matched.str(), Kind::Identifier); }}
  23. : reSearch(kReOperatorBracket)
  24. ? std::function{[]{ return toKind(matched.str()); }}
  25. : std::function{[]{ return Kind::Unknown; }}
  26. )(), // call the std::function that wraps a lambda
  27. matched.str(),
  28. });

huangapple
  • 本文由 发表于 2023年8月9日 01:07:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/76861789.html
匿名

发表评论

匿名网友

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

确定