gpt4 book ai didi

c++ - “卡住”一个表达式

转载 作者:太空狗 更新时间:2023-10-29 21:26:35 25 4
gpt4 key购买 nike

我有一个要“卡住”的 C++ 表达式。通过这个,我的意思是我有如下语法:

take x*x with x in container ...

其中 ... 表示进一步的(对这个问题没有用的)语法。但是,如果我尝试编译它,无论我使用什么预处理器翻译来“接受”一个“运算符”(在引号中,因为它在技术上不是一个运算符,但翻译阶段将它变成一个类,说, operator* 可用),编译器仍然尝试评估/找出 x*x 的来源,(并且,因为它之前没有被声明(因为它在'in'阶段进一步声明),相反)找不到它并抛出编译错误。

我目前的想法基本上涉及尝试将表达式放在 lambda 中(并且由于我们可以推断出容器的类型,我们可以将 x 声明为正确的类型,例如 [](decltype(*begin(container)) x) { return x*x } - 因此,当编译器查看此语句时,它是有效的并且没有抛出错误),但是,我正在运行实际实现这一目标的错误。

因此,我的问题是:有什么方法/什么是“卡住”我表达式的 x*x 部分的最佳方法?

编辑:为了澄清我的问题,请采取以下措施。假设运算符 - 以合理的方式定义,以便以下尝试实现上述 take ... 语法的作用:

MyTakeClass() - x*x - MyWithClass() - x - MyInClass() - 容器 ...

当这条语句被编译时,编译器会抛出一个错误; x 未声明,因此 x*x 没有意义(x - MyInClass() 等也没有)。我想要实现的是找到一种方法来编译上述表达式,使用任何可用的巫毒魔法,不知道 x 的类型(或者,事实上,它将被命名为 x ; 它可以提前命名为“somestupidvariablename”)。

最佳答案

我想出了一个几乎的解决方案,基于表达式模板(注意:这些不是表达式模板,它们是基于表达式模板)。不幸的是,我想不出一个不需要你预先声明的方法 x , 但我确实想出了一个延迟类型的方法,所以你只需要声明 x一个全局的,并且可以在同一个程序/文件/范围内一遍又一遍地将它用于不同的类型。这里是发挥魔力的表达式类型,我设计的非常灵活,你应该可以轻松地随意添加操作和使用。除了 x 的预声明外,它的使用完全按照您的描述进行。

我知道的缺点:它确实需要 T*T , T+T , 和 T(long)可编译。

expression x(0, true); //x will be the 0th parameter.  Sorry: required :(

int main() {
std::vector<int> container;
container.push_back(-3);
container.push_back(0);
container.push_back(7);
take x*x with x in container; //here's the magic line
for(unsigned i=0; i<container.size(); ++i)
std::cout << container[i] << ' ';

std::cout << '\n';
std::vector<float> container2;
container2.push_back(-2.3);
container2.push_back(0);
container2.push_back(7.1);
take 1+x with x in container2; //here's the magic line
for(unsigned i=0; i<container2.size(); ++i)
std::cout << container2[i] << ' ';

return 0;
}

这里是类和定义,使它全部工作:

class expression {
//addition and constants are unused, and merely shown for extendibility
enum exprtype{parameter_type, constant_type, multiplication_type, addition_type} type;
long long value; //for value types, and parameter number
std::unique_ptr<expression> left; //for unary and binary functions
std::unique_ptr<expression> right; //for binary functions

public:
//constructors
expression(long long val, bool is_variable=false)
:type(is_variable?parameter_type:constant_type), value(val)
{}
expression(const expression& rhs)
: type(rhs.type)
, value(rhs.value)
, left(rhs.left.get() ? std::unique_ptr<expression>(new expression(*rhs.left)) : std::unique_ptr<expression>(NULL))
, right(rhs.right.get() ? std::unique_ptr<expression>(new expression(*rhs.right)) : std::unique_ptr<expression>(NULL))
{}
expression(expression&& rhs)
:type(rhs.type), value(rhs.value), left(std::move(rhs.left)), right(std::move(rhs.right))
{}
//assignment operator
expression& operator=(expression rhs) {
type = rhs.type;
value = rhs.value;
left = std::move(rhs.left);
right = std::move(rhs.right);
return *this;
}

//operators
friend expression operator*(expression lhs, expression rhs) {
expression ret(0);
ret.type = multiplication_type;
ret.left = std::unique_ptr<expression>(new expression(std::move(lhs)));
ret.right = std::unique_ptr<expression>(new expression(std::move(rhs)));
return ret;
}
friend expression operator+(expression lhs, expression rhs) {
expression ret(0);
ret.type = addition_type;
ret.left = std::unique_ptr<expression>(new expression(std::move(lhs)));
ret.right = std::unique_ptr<expression>(new expression(std::move(rhs)));
return ret;
}

//skip the parameter list, don't care. Ignore it entirely
expression& operator<<(const expression&) {return *this;}
expression& operator,(const expression&) {return *this;}

template<class container>
void operator>>(container& rhs) {
for(auto it=rhs.begin(); it!=rhs.end(); ++it)
*it = execute(*it);
}
private:
//execution
template<class T>
T execute(const T& p0) {
switch(type) {
case parameter_type :
switch(value) {
case 0: return p0; //only one variable
default: throw std::runtime_error("Invalid parameter ID");
}
case constant_type:
return ((T)(value));
case multiplication_type:
return left->execute(p0) * right->execute(p0);
case addition_type:
return left->execute(p0) + right->execute(p0);
default:
throw std::runtime_error("Invalid expression type");
}
}
//This is also unused, and merely shown as extrapolation
template<class T>
T execute(const T& p0, const T& p1) {
switch(type) {
case parameter_type :
switch(value) {
case 0: return p0;
case 1: return p1; //this version has two variables
default: throw std::runtime_error("Invalid parameter ID");
}
case constant_type:
return value;
case multiplication_type:
return left->execute(p0, p1) * right->execute(p0, p1);
case addition_type:
return left->execute(p0, p1) + right->execute(p0, p1);
default:
throw std::runtime_error("Invalid expression type");
}
}
};
#define take
#define with <<
#define in >>

编译并运行并在 http://ideone.com/Dnb50 处输出正确的输出

您可能会注意到自 x必须预先声明,with部分被完全忽略。这里几乎没有宏魔法,宏有效地将它变成“x*x >> x << container”,其中>>x什么都不做。所以表达式有效x*x << container”。

另请注意,此方法很慢,因为这是一个解释器,几乎所有的减速都意味着。但是,它的好处是它是可序列化的,您可以将函数保存到文件中,稍后加载它,然后然后执行它。

R.MartinhoFernandes观察到 x 的定义可以简化为expression x; , 它可以从 with 中推导出参数的顺序部分,但这需要对设计进行大量重新思考,并且会更加复杂。稍后我可能会回来添加该功能,但与此同时,我知道这绝对是可能的。


如果您可以将表达式修改为“take(x*x with x in container)”,那么就无需预先声明“x”,这比表达式模板简单得多。 #定义, #定义在, #define take(expr, var, con)\ std::transform(con.begin(), con.end(), con.begin(),\ [](const typename con::value_type& var) -> typename con::value_type\ {返回表达式;});
int main() {
std::vector<int> container;
container.push_back(-3);
container.push_back(0);
container.push_back(7);
take(x*x with x in container); //here's the magic line
for(unsigned i=0; i<container.size(); ++i)
std::cout << container[i] << ' ';
}

关于c++ - “卡住”一个表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11009233/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com