非法使用类型作为表达式

时间:2011-12-09 15:39:07

标签: c++ visual-studio-2010 c++11

我遇到了一些令人讨厌的问题但是看不到错误。我有一个模板功能

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;
}

2 个答案:

答案 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(); });
}