英文:
I do not understand why error(incompatible operand types) occurred in my c++ code
问题
我用C++编写了一个用于分析JavaScript代码词法单元的代码。以下是相应的函数。为了参考,Kind
是一个包含词法单元类型的枚举类,函数toKind
的定义在函数analyzeLexeme
的下方。
auto analyzeLexeme(std::wstring & source_code) -> std::vector<Token> {
using std::__1::wregex;
using std::regex_search;
using std::vector;
using std::wsmatch;
using std::wstring;
using std::string;
using std::tuple;
using std::map;
wsmatch matched;
Kind result_kind;
map<string, bool> context = { { "in_tmplt", false }, };
auto result = vector<Token>();
auto reSearch = [&source_code, &matched] (const wregex & re) {
return regex_search(source_code, matched, re);
};
source_code += L'\0';
for (; source_code[0]; source_code = matched.suffix()) {
if (reSearch(kReWhiteSpace)) continue;
result.push_back({(
reSearch(kReNumLiteral) ? [] { return Kind::NumberLiteral; } :
reSearch(kReStrLiteral) ? [] { return Kind::StringLiteral; } :
reSearch(kReTmpltHdLiteral) && !context["in_tmplt"] ?
[&] {
context["in_tmplt"] = true;
return Kind::TemplateHeadLiteral;
} :
reSearch(kReTmpltTlLiteral) && context["in_tmplt"] ?
[&] {
context["in_tmplt"] = false;
return Kind::TemplateTailLiteral;
} :
reSearch(kReTmpltMdLiteral) && context["in_tmplt"] ? [] { return Kind::TemplateMiddleLiteral; } :
reSearch(kReTmpltLiteral) ? [] { return Kind::TemplateLiteral; } :
reSearch(kReIdentifierKyword) ? [&] { return toKind(matched.str(), Kind::Identifier); } :
reSearch(kReOperatorBracket) ? [&] { return toKind(matched.str()); } :
[] { return Kind::Unknown; }
)(),
matched.str(),
});
if (result.back().kind == Kind::Unknown) {
std::wcerr << L"[ERR] : Unknown Token : " << source_code.substr(0, 40) << std::endl;
// fwprintf(stderr, L"[ERR] : Unknown Token : %s", source_code.substr(0, 40).c_str());
exit(1);
}
}
return result;
}
// str_to_kind is a map(string to kind).
auto toKind(std::wstring str, Kind default_kind) -> Kind {
return str_to_kind.count(str) ? str_to_kind.at(str) : default_kind;
}
错误出现在这里(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
.
auto analyzeLexeme(std::wstring & source_code) -> std::vector<Token> {
using std::__1::wregex;
using std::regex_search;
using std::vector;
using std::wsmatch;
using std::wstring;
using std::string;
using std::tuple;
using std::map;
wsmatch matched;
Kind result_kind;
map<string, bool> context = { { "in_tmplt", false }, };
auto result = vector<Token>();
auto reSearch = [&source_code, &matched] (const wregex & re) {
return regex_search(source_code, matched, re);
};
source_code += L'\0';
for (; source_code[0]; source_code = matched.suffix()) {
if (reSearch(kReWhiteSpace)) continue;
result.push_back({(
reSearch(kReNumLiteral) ? [] { return Kind::NumberLiteral; } :
reSearch(kReStrLiteral) ? [] { return Kind::StringLiteral; } :
reSearch(kReTmpltHdLiteral) && !context["in_tmplt"] ?
[&] {
context["in_tmplt"] = true;
return Kind::TemplateHeadLiteral;
} :
reSearch(kReTmpltTlLiteral) && context["in_tmplt"] ?
[&] {
context["in_tmplt"] = false;
return Kind::TemplateTailLiteral;
} :
reSearch(kReTmpltMdLiteral) && context["in_tmplt"] ? [] { return Kind::TemplateMiddleLiteral; } :
reSearch(kReTmpltLiteral) ? [] { return Kind::TemplateLiteral; } :
reSearch(kReIdentifierKyword) ? [&] { return toKind(matched.str(), Kind::Identifier); } :
reSearch(kReOperatorBracket) ? [&] { return toKind(matched.str()); } :
[] { return Kind::Unknown; }
)(),
matched.str(),
});
if (result.back().kind == Kind::Unknown) {
std::wcerr << L"[ERR] : Unknown Token : " << source_code.substr(0, 40) << std::endl;
// fwprintf(stderr, L"[ERR] : Unknown Token : %s", source_code.substr(0, 40).c_str());
exit(1);
}
}
return result;
}
// str_to_kind is a map(string to kind).
auto toKind(std::wstring str, Kind default_kind) -> Kind {
return str_to_kind.count(str) ? str_to_kind.at(str) : default_kind;
}
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
。如果您想要有一个返回一种类型或另一种类型的表达式,您需要某种类型的类型擦除。
考虑以下代码:
std::any test = rand() > 10 ? 42 : "a";
尽管您正在构造一个std::any
,但是三元操作符的两个操作数的类型不同,且彼此之间不能转换。
但是以下代码可以正常工作:
std::any test = rand() > 10 ? std::any{42} : std::any{"a"};
然而,您似乎在表达式中立即调用函数。考虑到这一点,您还可以删除所有单语句的lambda,并在三元操作符内部调用多语句。
如果您在现场调用它们,代码将如下所示:
result.push_back({
(
reSearch(kReNumLiteral)
? Kind::NumberLiteral
: reSearch(kReStrLiteral)
? Kind::StringLiteral
: reSearch(kReTmpltHdLiteral) && !context["in_tmplt"]
? [&] {
context["in_tmplt"] = true;
return Kind::TemplateHeadLiteral;
}() // 在这里调用!
: reSearch(kReTmpltTlLiteral) && context["in_tmplt"]
? [&] {
context["in_tmplt"] = false;
return Kind::TemplateTailLiteral;
}() // 再次在这里调用,lambda被调用。
: reSearch(kReTmpltMdLiteral) && context["in_tmplt"]
? Kind::TemplateMiddleLiteral
: reSearch(kReTmpltLiteral)
? Kind::TemplateLiteral;
: reSearch(kReIdentifierKyword)
? toKind(matched.str(), Kind::Identifier)
: reSearch(kReOperatorBracket)
? toKind(matched.str())
: Kind::Unknown
),
matched.str(),
});
如果您将它们全部包装在像std::function
这样的类型擦除包装器中,代码将如下所示:
result.push_back({
(
reSearch(kReNumLiteral)
? std::function{[]{ return Kind::NumberLiteral; }}
: reSearch(kReStrLiteral)
? std::function{[]{ return Kind::StringLiteral; }}
: reSearch(kReTmpltHdLiteral) && !context["in_tmplt"]
? std::function{[&] {
context["in_tmplt"] = true;
return Kind::TemplateHeadLiteral;
}}
: reSearch(kReTmpltTlLiteral) && context["in_tmplt"]
? std::function{[&] {
context["in_tmplt"] = false;
return Kind::TemplateTailLiteral;
}}
: reSearch(kReTmpltMdLiteral) && context["in_tmplt"]
? std::function{[]{ return Kind::TemplateMiddleLiteral; }}
: reSearch(kReTmpltLiteral)
? std::function{[]{ return Kind::TemplateLiteral; }}
: reSearch(kReIdentifierKyword)
? std::function{[]{ return toKind(matched.str(), Kind::Identifier); }}
: reSearch(kReOperatorBracket)
? std::function{[]{ return toKind(matched.str()); }}
: std::function{[]{ return Kind::Unknown; }}
)(), // 调用包装了lambda的std::function
matched.str(),
});
英文:
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:
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:
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:
result.push_back({
(
reSearch(kReNumLiteral)
? Kind::NumberLiteral
: reSearch(kReStrLiteral)
? Kind::StringLiteral
: reSearch(kReTmpltHdLiteral) && !context["in_tmplt"]
? [&] {
context["in_tmplt"] = true;
return Kind::TemplateHeadLiteral;
}() // here!
: reSearch(kReTmpltTlLiteral) && context["in_tmplt"]
? [&] {
context["in_tmplt"] = false;
return Kind::TemplateTailLiteral;
}() // here again, lambda called.
: reSearch(kReTmpltMdLiteral) && context["in_tmplt"]
? Kind::TemplateMiddleLiteral
: reSearch(kReTmpltLiteral)
? Kind::TemplateLiteral;
: reSearch(kReIdentifierKyword)
? toKind(matched.str(), Kind::Identifier)
: reSearch(kReOperatorBracket)
? toKind(matched.str())
: Kind::Unknown
),
matched.str(),
});
Here's how it look like if you wrap them all in a type erasure wrapper like std::function
:
result.push_back({
(
reSearch(kReNumLiteral)
? std::function{[]{ return Kind::NumberLiteral; }}
: reSearch(kReStrLiteral)
? std::function{[]{ return Kind::StringLiteral; }}
: reSearch(kReTmpltHdLiteral) && !context["in_tmplt"]
? std::function{[&] {
context["in_tmplt"] = true;
return Kind::TemplateHeadLiteral;
}}
: reSearch(kReTmpltTlLiteral) && context["in_tmplt"]
? std::function{[&] {
context["in_tmplt"] = false;
return Kind::TemplateTailLiteral;
}}
: reSearch(kReTmpltMdLiteral) && context["in_tmplt"]
? std::function{[]{ return Kind::TemplateMiddleLiteral; }}
: reSearch(kReTmpltLiteral)
? std::function{[]{ return Kind::TemplateLiteral; }}
: reSearch(kReIdentifierKyword)
? std::function{[]{ return toKind(matched.str(), Kind::Identifier); }}
: reSearch(kReOperatorBracket)
? std::function{[]{ return toKind(matched.str()); }}
: std::function{[]{ return Kind::Unknown; }}
)(), // call the std::function that wraps a lambda
matched.str(),
});
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论