选择模板化运算符实现

时间:2016-10-04 15:52:27

标签: c++ templates

假设我们在自定义类上有operator/

struct my_class {
    uint64_t value;
}

template<class T>
constexpr T operator/(const my_class& a, const my_class& b)
{
    return static_cast<T>(a.value) / static_cast<T>(b.value);
}

如何选择a / b(其中ab属于my_class类型)返回intdouble,例如?

3 个答案:

答案 0 :(得分:5)

您可以使用一些模板魔术和转换运算符。您可以先为表达式定义一个简单的包装器:

SELECT t1.IDtag,
       t1.Name,
       GROUP_CONCAT(COALESCE(t2.Record, 'no rap sheet'))
FROM Table1 t1
LEFT JOIN Table2 t2
    ON t1.IDtag = t2.IDtag
GROUP BY t1.IDtag

然后,可以像这样重载运算符:

struct DivideMyClass {
    DivideMyClass(const MyClass& lhs_, const MyClass& rhs_) : lhs{lhs_}, rhs_{rhs} {}

    template<typename T>
    operator T () const {
        return static_cast<T>(lhs.value) / static_cast<T>(rhs.value);
    }

private:
    const MyClass& lhs;
    const MyClass& rhs;
};

然后您的代码将如下所示:

constexpr DivideMyClass operator/(const my_class& a, const my_class& b)
{
    return DivideMyClass{a, b};
}

为什么这个解决方案不好

语言不会通过返回类型重载除法。你的代码会混淆其他思维,这是一个错误。如果你广泛使用这种方法,你最终会得到一个令人难以理解的代码。

另一方面,转换是隐含的,并且没有任何内容表明在呼叫站点的运营商中是否确实进行了转换。

您将阻止AAA idom(几乎总是使用自动)。 double d = MyClass{21} / MyClass{5}; // will be equal to 4.2 可能会破坏您的代码,这是一件坏事。

这样的技术应该用于模板表达和类似的东西。使用它进行简单的划分会使其他人感到困惑。

答案 1 :(得分:3)

  

我可以根据接受结果的变量类型进行选择吗?即INT   result = a / b返回int,但是double result = a / b返回double?

如果你一心想做到这一点你可以,但它很复杂,我不会推荐它。你必须仔细权衡利益与引入的复杂性。你可以通过懒惰的评估来做到这一点:

struct X {
  int value;
};

struct X_op_proxy {
  const X& lhs;
  const X& rhs;

  template <class T>
  operator T() const { return static_cast<T>(lhs.value) / static_cast<T>(rhs.value); }
};
auto operator/(const X& lhs, const X& rhs) -> X_op_proxy
{
    return {lhs, rhs};
}

int main()
{
  X x1{11}, x2{2};

  int i = x1 / x2;
  cout << i << endl;

  float f = x1 / x2;
  cout << f << endl;
}

这是最低限度,因此您可以弄清楚这项技术的用途。您可以根据自己的需要调整并发展它。

答案 2 :(得分:2)

要选择特定的操作员模板,您必须将其称为功能:

auto result = operator/<double>(my_class{4}, my_class{2});
// result is 2.0