I've got a nasty problem with some code and can't see the error. I have a template function
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);
}
with the obvious implementation of make_unique
. There are other overloads, but they differ in obvious ways like different parameter numbers, so I know that this is the only one being called. Then I call it, like so (this is the error line, 315):
RecursiveParseLeftAssociativeBinaryExpression<Wide::Parser::AccessExpression>(current_expression, [&] { return this_ptr->RecursiveParseExpression(); });
But the compiler insists that I am using a type as an expression. I'm pretty sure that this code is completely legal. Am I missing something? The error is
1>parser.cpp(315): error C2275: 'Wide::Parser::AccessExpression' : illegal use of this type as an expression
Edit: These are the definitions of the other overloads.
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);
}
However, they clearly differ in requiring additional explicit template arguments, and so cannot be the call resolved.
Edit: The definition of make_unique
:
namespace Wide {
template<typename T> std::unique_ptr<T> make_unique() {
return std::unique_ptr<T>(new T);
}
};
Just to be certain, the calling code isn't in any template of any kind, and there are absolutely no dependent names. Wide
is a namespace.
Another edit: The error is repeated for all the direct calls to this overload, but not for the ones which are called through the other overloads, curiously.
Edit: This 100line test case reproduces the problem.
#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;
}