如何将类似运算符的表达式声明为函数调用?

时间:2014-12-06 00:26:39

标签: c++

目标:

描述一种提供函数调用的方法,使得对于给定的函数" T F(T a,T b)"表达" E"在代码中写成" aEb"将该功能称为" F(a,b)"!

动机:

提供缩写形式的函数调用,当某种语法会增加代码与标准格式的清晰度时。

示例:

#include <iostream>
#include <random>
#include <valarray>

using namespace std;

constexpr unsigned int SIDES = 20u;

random_device RNDNGEN;
uniform_int_distribution<unsigned int> DICE[SIDES];

// Function to be called via in-order
unsigned int operatorD(unsigned int number, unsigned int sides)
{
  valarray<unsigned int> dice(number);

  for(unsigned int & i : dice)
  {
    i = DICE[sides](RNDNGEN);
  }

  return dice.sum();
}

int main()
{
  // desired call syntax
  int x = 1 + 1d6;   // executes operator=(x, operator+(1, operatorD(1, 6)))
  cout << x << endl; // displays a number in [2, 7]
}

请注意,所选表达式d不能与表达式&#34; 1.d&#34;碰撞,因为该点需要点,而d后面可能没有数字。

函数的名称和符号化表达式(在示例&#34; operatorD&#34;&#34; d&#34;)中是否需要相同是不太重要的;如果两种情况都可能,那将是一个奖励。

失败的解决方案尝试:

1)运营商定义

运算符定义不是C ++的功能,如here所述。

2)宏定义

#define指令不支持显式参数定义:

#define (x)D(y) D(x,y)
// error: macro names must be identifiers
#define xDy D(x,y)
// does not recognise x and y as variables

可能的解决方案我真的不想使用:

1)运算符使用如here

所述的函数对象重载

每次明显调用的真函数调用次数增加三倍。

相关问题:

使用语法&#39; x = M [row] [column]&#39;访问一维数组M作为矩阵。 有必要为两个不同类别的对象定义operator []的两个重载:矩阵和向量(行或列)。 一个M [行] [列]&#39;然后,调用从M [row]创建一个匿名向量,在该行上执行[column]。 ......每一个&#39; M [row]&#39;然后调用从构造函数生成一个对象,在其上只调用一次自己的成员函数operator [],然后立即丢弃(匿名)。

在准数学符号中使用矩阵运算:

class Matrix
{
  Matrix invert();
  Matrix transpose();
};

Matrix m;
// m = m.invert();
m = m^-1;    // Assuming here that the whole "^-1" were the call sign.
m = m sup-1; // Assuming here that the whole "sup-1" were the call sign.
// m = m.transpose();
m = m^T;    // Dito here; the 'T' is not supposed to be a separate Token.
m = m supT; // This should work in spite of operator^, as it would not be defined for a custom Matrix class.

隐藏对象的封装:

class Value
{
  member x;
};
class EncapsulatedValue<Value T>
{
  T value;

  EncapsulatedValue(T value) : value{value}
  {}

  member x()
  {
    member y = T.x;
    /* modifies y */
    return y;
  }
};

Value temp;
EncapsulatedValue v(temp);
member z;
// z = v.x();
z = v.x;

2 个答案:

答案 0 :(得分:0)

你不能在内置类型(或原始指针)的参数上重载运算符。

除此之外,您可以随心所欲地做任何事情。

问题是什么?

答案 1 :(得分:0)

这只是部分答案,但可能会因额外输入而改善 来自Yakk和sp2danny的指针给我带来了这么远。

可以通过以这种方式定义用户文字来部分解决骰子示例:

unsigned int operator"" d6(unsigned long long int number)
{
  return operatorD(number, 6u);
}

显然,operatorD可以完全在这个文字定义中实现,因此不需要引入额外的运行时开销。

这确实可以称为:

unsigned int x = 4 + 3d6;

但请注意,当运算符“”名称不以下划线开头时,g ++将发出警告,标准化委员会保留所有未加前缀的名称。

缺少的部分在于必须将operatorD的第二个参数(要抛出的骰子的边)编码到文字标签中,即:明确地定义所有可用作文字的骰子。

使用这种技术似乎不可能在两侧使用变量实现,例如在operator +上看到的实现:

unsigned int operator"" d(unsigned long long int number, unsigned long long int sides) // Parameters like on operator+
{
  return operatorD(number, sides);
}
// error: [...] has invalid argument list

正如定义前缀而不是后缀似乎不是:

unsigned int operator"" d(unsigned long long int size, int) // Parameters like on postfix operator++
{
  return operatorD(1, size);
}
// same error
// Comparing the d6 variant with operator++ signature already provided a dead giveaway:
// The postfix operator++ has the spoof parameter, the postfix user literal does not.

有趣的是,使用如展示here的可变参数模板确实应该允许定义具有任意数量参数的后序操作符。

为了完全解决这个例子,仍然需要产生一个适用于任意数量边的代码,以便例如写入“3d13”并没有突然失败,因为之前没有明确宣布过“d13”后缀。


通过使用表达式模板和以here描述的方式重载operator [],可以独立于此解决上述但未解释的第一个矩阵示例。

其他提到的矩阵示例可以通过单个用户定义的后缀来解决:

Matrix operator"" T(Matrix & m)
{
  return m.transpose();
}

如果只有用户文字可以定义为类而不仅仅是基元。


到目前为止,已有四分之一;最好的例子至少部分解决了...
但肯定可以做得更好!?