C ++与D的例子。来自D主页比较的前端程序RPN计算器

时间:2015-10-20 06:45:44

标签: c++ d c++14

在D网站上,当您进入网站时,前端会显示一个RPN计算器示例。 由于D是我强大的元编程的参考(除了Lisp), 我想知道如何将一段代码从C ++转换为D.代码片段不需要相同,但应该是相似的。我放弃了使用宏:

部分D版本:

Array!int stack;
void binop(string op)()
{
    stack[$ - 2] = mixin("stack[$ - 2] " ~
                         op ~ " stack[$ - 1]");
    stack.removeBack();
    writeln(stack[$ - 1]);
}

void process(in char[] token)
{
    alias Ops = AliasSeq!("+", "-", "*", "/", "%");
Lswitch:
    switch (token)
    {
        foreach (op; Ops)
        {
    case op:
            binop!op();
            break Lswitch;
        }

    case "=":
        writeln(stack[$ - 1]);
        stack.removeBack();
        break;

    default:
        stack.insertBack(token.to!int);
        break;
    }
}

部分C ++版本在某些实用程序的帮助下:

template <char Op>
void binop(std::vector<int> & s) {
   //Returns std::minus<>, std::plus<>, etc.
   using Op_t = opstr_to_func_object_t<Op>;

   s[s.size() - 2] = Op_t{}(s[s.size() - 2], s[s.size() - 1]);
   s.pop_back();
   std::cout << s[s.size() - 1] << '\n';
} 

template <char Op>
constexpr char op_name<Op> = std::integral_constant<char, Op>;

void process (std::string const & token, vector<int> & s) {
   using namespace std;
   constexpr auto ops = make_tuple(op_name<'+'>,
                                op_name<'-'>,
                                op_name<'*'>,
                                op_name<'/'>,
                                op_name<'%'>);

   Lswitch:
   switch (token[0]) {
     //Cannot expand cases inline

       // foreach([&](auto && elem) {
       //         constexpr auto op_str = decltype(elem)::value
       //
       //     }, Ops{});

      case "=":
          std::cout << s[s.size() - 1] << '\n';
          s.pop_back();
          break;
      default:
          s.push_back(stoi(token));
    }
 }

我有一些问题:

  1. 有没有办法扩展内联代码并将其与环境或内容混合使用 在不使用宏的情况下扩展D中的优化开关?在D中,有一个foreach可以扩展内联代码。

  2. 有没有办法在constexpr的帮助下为字符串模拟开关?

  3. 我使用外部函数和模板参数,因为它似乎 lambdas不能指定模板参数,所以我必须使用一个详细的函数对象来捕获堆栈和模板化的operator()()。有没有办法解决这个并保持 主要的功能进程和binop?

  4. 我认为D版在元编程领域得分很高, 但是想知道如何在C ++中做到最好。

1 个答案:

答案 0 :(得分:2)

如果目标是干净的代码和/或尽可能多地使用语言功能,尝试将语言1的某些代码直接翻译为语言2很少是最佳解决方案。重写你的RPN计算器而忽略D实现可能会更好......好吧,你的问题:

<强> 1)
Tldr:不是直接的。
eval的扩展案例构造在其原始语法中没有宏,只是不存在。 (而std::map之类的东西并不存在,C ++是一种&#34;硬编译的语言,没有任何解释器,程序中没有嵌入式编译器。)
但由于这里的所有内容都基于仿函数/ lambdas,为什么不制作一个映射(switch或其他任何东西)来将符号映射到函数,然后只调用符号函数而不使用switch

<强> 2)
是的,这是可能的。
constexpr仅适用于整数,但正如您所说,可以使用case myhashfunction("stringvalue"): ... constexpr unsigned long myhashfunction(const char *) {...} 函数获取字符串并返回一个int,其中不同的字符串将映射到不同的int(希望如此)。 /> 案件看起来像

case "stringvalue"_hash:

或者,用户定义的文字,例如

auto

有人实际实施了CRC32:https://stackoverflow.com/a/9842857/3134621

第3)
Tldr:如果它应该在函数内部,没有。
虽然lambdas中的{{1}}关键字具有一些类似模板的功能,但它没有全功能模板那么强大(例如,没有文字,没有强制多个参数的相同类型等等)。
在函数中创建一个没有lambda语法快捷方式的仿函数类也是不可能的:函数中的类定义可能不使用模板。
因此,您将需要使用lambda / functor的函数之外的东西。