我遇到了一些令人讨厌的问题但是看不到错误。我有一个模板功能
template<typename T, typename F> void RecursiveParseLeftAssociativeBinaryExpression(std::unique_ptr<Wide::Parser::ExpressionAST>& cur_expr, F f) {
CheckedIncrement();
auto new_expr = Wide::make_unique<T>();
new_expr->lhs = std::move(cur_expr);
new_expr->rhs = f();
cur_expr = std::move(new_expr);
}
明确实施make_unique
。还有其他重载,但它们有明显的不同,如不同的参数号,所以我知道这是唯一被调用的。然后我这样称呼它(这是错误行,315):
RecursiveParseLeftAssociativeBinaryExpression<Wide::Parser::AccessExpression>(current_expression, [&] { return this_ptr->RecursiveParseExpression(); });
但是编译器坚持认为我使用了一个类型作为表达式。我很确定这段代码完全合法。我错过了什么吗?错误是
1>parser.cpp(315): error C2275: 'Wide::Parser::AccessExpression' : illegal use of this type as an expression
编辑:这些是其他重载的定义。
template<typename First, Wide::Lexer::TokenType first, typename F> std::unique_ptr<Wide::Parser::ExpressionAST> RecursiveParseLeftAssociativeBinaryExpression(F next) {
auto cur_expr = next();
std::function<void()> RecursiveParseSingleToken;
RecursiveParseSingleToken = [&] {
switch(begin->type) {
case first:
RecursiveParseLeftAssociativeBinaryExpression<First>(cur_expr, next);
return RecursiveParseSingleToken();
}
};
RecursiveParseSingleToken();
return std::move(cur_expr);
}
template<typename First, typename Second, Wide::Lexer::TokenType first, Wide::Lexer::TokenType second, typename F> std::unique_ptr<Wide::Parser::ExpressionAST>
RecursiveParseLeftAssociativeBinaryExpression(F next) {
auto cur_expr = next();
std::function<void()> RecursiveParseDualToken;
RecursiveParseDualToken = [&] {
switch(begin->type) {
case first:
RecursiveParseLeftAssociativeBinaryExpression<First>(cur_expr, next);
return RecursiveParseDualToken();
case second:
RecursiveParseLeftAssociativeBinaryExpression<Second>(cur_expr, next);
return RecursiveParseDualToken();
}
};
RecursiveParseDualToken();
return std::move(cur_expr);
}
但是,它们明显不同,需要额外的显式模板参数,因此无法解析调用。
修改:make_unique
的定义:
namespace Wide {
template<typename T> std::unique_ptr<T> make_unique() {
return std::unique_ptr<T>(new T);
}
};
可以肯定的是,调用代码不在任何类型的模板中,并且绝对没有依赖名称。 Wide
是名称空间。
另一个编辑:对于此重载的所有直接调用都会重复该错误,但是对于通过其他重载调用的那些而不是,这很奇怪。
编辑:这个100行测试用例重现了这个问题。
#include <memory>
#include <functional>
#include <vector>
namespace Wide {
template<typename T> std::unique_ptr<T> make_unique() {
return std::unique_ptr<T>(new T);
}
class Lexer {
public:
enum TokenType {
Namespace,
For,
Identifier
};
struct Token {
TokenType type;
};
};
class Parser {
public:
struct ExpressionAST {};
struct BinaryExpressionAST : public ExpressionAST {
std::unique_ptr<ExpressionAST> lhs;
std::unique_ptr<ExpressionAST> rhs;
};
struct AccessExpression : public BinaryExpressionAST {};
struct IdentifierExpression : public ExpressionAST {};
};
}
typedef std::vector<Wide::Lexer::Token>::iterator Iterator;
struct inner_parser {
Iterator begin, end;
std::unique_ptr<Wide::Parser::ExpressionAST> RecursiveParsePrimaryExpression() {
if (begin->type == Wide::Lexer::TokenType::Identifier) {
CheckedIncrement();
return Wide::make_unique<Wide::Parser::IdentifierExpression>();
}
throw std::runtime_error("aah");
}
template<typename T, typename F> void RecursiveParseLeftAssociativeBinaryExpression(std::unique_ptr<Wide::Parser::ExpressionAST>& cur_expr, F f) {
CheckedIncrement();
auto new_expr = Wide::make_unique<T>();
new_expr->lhs = std::move(cur_expr);
new_expr->rhs = f();
cur_expr = std::move(new_expr);
}
template<typename First, Wide::Lexer::TokenType first, typename F> std::unique_ptr<Wide::Parser::ExpressionAST>
RecursiveParseLeftAssociativeBinaryExpression(F next) {
auto cur_expr = next();
std::function<void()> RecursiveParseSingleToken;
RecursiveParseSingleToken = [&] {
switch(begin->type) {
case first:
RecursiveParseLeftAssociativeBinaryExpression<First>(cur_expr, next);
return RecursiveParseSingleToken();
}
};
RecursiveParseSingleToken();
return std::move(cur_expr);
}
template<typename First, typename Second, Wide::Lexer::TokenType first, Wide::Lexer::TokenType second, typename F>
std::unique_ptr<Wide::Parser::ExpressionAST>
RecursiveParseLeftAssociativeBinaryExpression(F next) {
auto cur_expr = next();
std::function<void()> RecursiveParseDualToken;
RecursiveParseDualToken = [&] {
switch(begin->type) {
case first:
RecursiveParseLeftAssociativeBinaryExpression<First>(cur_expr, next);
return RecursiveParseDualToken();
case second:
RecursiveParseLeftAssociativeBinaryExpression<Second>(cur_expr, next);
return RecursiveParseDualToken();
}
};
RecursiveParseDualToken();
return std::move(cur_expr);
}
void CheckedIncrement() {
if (begin == end)
throw std::runtime_error("aaaaaah!");
begin++;
}
};
int main() {
std::vector<Wide::Lexer::Token> tokens;
inner_parser ip;
ip.begin = tokens.begin();
ip.end = tokens.end();
auto ret = ip.RecursiveParseLeftAssociativeBinaryExpression<Wide::Parser::AccessExpression, Wide::Lexer::TokenType::For>([&] { return ip.RecursiveParsePrimaryExpression(); });
return 0;
}
答案 0 :(得分:2)
在模板成员函数'lambdas中自由地喷洒this->
似乎可以修复你的测试用例:
#include <memory>
#include <functional>
#include <vector>
namespace Wide {
template<typename T> std::unique_ptr<T> make_unique() {
return std::unique_ptr<T>(new T);
}
class Lexer {
public:
enum TokenType {
Namespace,
For,
Identifier
};
struct Token {
TokenType type;
};
};
class Parser {
public:
struct ExpressionAST {};
struct BinaryExpressionAST : public ExpressionAST {
std::unique_ptr<ExpressionAST> lhs;
std::unique_ptr<ExpressionAST> rhs;
};
struct AccessExpression : public BinaryExpressionAST {};
struct IdentifierExpression : public ExpressionAST {};
};
}
typedef std::vector<Wide::Lexer::Token>::iterator Iterator;
struct inner_parser {
Iterator begin, end;
std::unique_ptr<Wide::Parser::ExpressionAST> RecursiveParsePrimaryExpression() {
if (begin->type == Wide::Lexer::Identifier) {
CheckedIncrement();
return Wide::make_unique<Wide::Parser::IdentifierExpression>();
}
throw std::runtime_error("aah");
}
template<typename T, typename F> void RecursiveParseLeftAssociativeBinaryExpression(std::unique_ptr<Wide::Parser::ExpressionAST>& cur_expr, F f) {
CheckedIncrement();
auto new_expr = Wide::make_unique<T>();
new_expr->lhs = std::move(cur_expr);
new_expr->rhs = f();
cur_expr = std::move(new_expr);
}
template<typename First, Wide::Lexer::TokenType first, typename F> std::unique_ptr<Wide::Parser::ExpressionAST>
RecursiveParseLeftAssociativeBinaryExpression(F next) {
auto cur_expr = next();
std::function<void()> RecursiveParseSingleToken;
RecursiveParseSingleToken = [&] {
switch(this->begin->type) {
case first:
this->RecursiveParseLeftAssociativeBinaryExpression<First>(cur_expr, next);
return RecursiveParseSingleToken();
}
};
RecursiveParseSingleToken();
return std::move(cur_expr);
}
template<typename First, typename Second, Wide::Lexer::TokenType first, Wide::Lexer::TokenType second, typename F>
std::unique_ptr<Wide::Parser::ExpressionAST>
RecursiveParseLeftAssociativeBinaryExpression(F next) {
auto cur_expr = next();
std::function<void()> RecursiveParseDualToken;
RecursiveParseDualToken = [&] {
switch(this->begin->type) {
case first:
this->RecursiveParseLeftAssociativeBinaryExpression<First>(cur_expr, next);
return RecursiveParseDualToken();
case second:
this->RecursiveParseLeftAssociativeBinaryExpression<Second>(cur_expr, next);
return RecursiveParseDualToken();
}
};
RecursiveParseDualToken();
return std::move(cur_expr);
}
void CheckedIncrement() {
if (begin == end)
throw std::runtime_error("aaaaaah!");
begin++;
}
};
int main() {
std::vector<Wide::Lexer::Token> tokens;
inner_parser ip;
ip.begin = tokens.begin();
ip.end = tokens.end();
auto ret = ip.RecursiveParseLeftAssociativeBinaryExpression<Wide::Parser::AccessExpression, Wide::Lexer::For>([&] { return ip.RecursiveParsePrimaryExpression(); });
return 0;
}
我推测这是VC ++ 2010的lambda实现中的一个错误,其中对于成员模板没有正确执行类范围名称解析。
答案 1 :(得分:1)
在您可以思考的任何地方散布typename
后,在template
之前包含<
的任何合格电话后,请(
。 template
紧跟在::
之后。
像这样:
auto new_expr = Wide::template make_unique<T>();
<强>更新强>
不知道这是否有帮助,但我反过来设计了一个问题来创建一个最小的完整编译(但不是链接)程序。不幸的是,它没有复制症状。但也许它会有助于追踪问题。或者至少可以让我觉得我在几个地方有多接近。 ; - )
#include <memory>
#include <functional>
namespace Wide {
template<typename T> std::unique_ptr<T> make_unique() {
return std::unique_ptr<T>(new T);
}
namespace Lexer
{
enum TokenType {first, second};
}
namespace Parser
{
struct ExpressionAST {};
struct AccessExpression
: public ExpressionAST
{
std::unique_ptr<ExpressionAST> lhs;
std::unique_ptr<ExpressionAST> rhs;
};
}
};
struct
{
Wide::Lexer::TokenType type;
}* begin;
template<typename First, Wide::Lexer::TokenType first, typename F> std::unique_ptr<Wide::Parser::ExpressionAST>
RecursiveParseLeftAssociativeBinaryExpression(F next) {
auto cur_expr = next();
std::function<void()> RecursiveParseSingleToken;
RecursiveParseSingleToken = [&] {
switch(begin->type) {
case first:
RecursiveParseLeftAssociativeBinaryExpression<First>(cur_expr, next);
return RecursiveParseSingleToken();
}
};
RecursiveParseSingleToken();
return std::move(cur_expr);
}
template<typename First, typename Second, Wide::Lexer::TokenType first, Wide::Lexer::TokenType second, typename F>
std::unique_ptr<Wide::Parser::ExpressionAST>
RecursiveParseLeftAssociativeBinaryExpression(F next) {
auto cur_expr = next();
std::function<void()> RecursiveParseDualToken;
RecursiveParseDualToken = [&] {
switch(begin->type) {
case first:
RecursiveParseLeftAssociativeBinaryExpression<First>(cur_expr, next);
return RecursiveParseDualToken();
case second:
RecursiveParseLeftAssociativeBinaryExpression<Second>(cur_expr, next);
return RecursiveParseDualToken();
}
};
RecursiveParseDualToken();
return std::move(cur_expr);
}
void CheckedIncrement();
template<typename T, typename F>
void RecursiveParseLeftAssociativeBinaryExpression(std::unique_ptr<Wide::Parser::ExpressionAST>& cur_expr, F f) {
CheckedIncrement();
auto new_expr = Wide::make_unique<T>();
new_expr->lhs = std::move(cur_expr);
new_expr->rhs = f();
cur_expr = std::move(new_expr);
}
struct A
{
std::unique_ptr<Wide::Parser::AccessExpression> RecursiveParseExpression();
};
int main()
{
std::unique_ptr<Wide::Parser::ExpressionAST> current_expression;
A* this_ptr;
RecursiveParseLeftAssociativeBinaryExpression<Wide::Parser::AccessExpression>(current_expression,
[&] { return this_ptr->RecursiveParseExpression(); });
}