C ++中的非常自动的运算符生成器 [英] Very automatic operator generator in C++

查看:89
本文介绍了C ++中的非常自动的运算符生成器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C ++有一个很好的习惯用法,它允许人们编写自动满足运算符之间某些关系的类.例如,这允许定义operator==,而不必再去定义operator!=.这就是Boost.Operators背后的想法.

C++ has a nice idiom that allows one to write classes that automatically fulfill certain relations between operators. For example this allows to define operator== and not bother to defined operator!= as well. This is the idea behind Boost.Operators.

这是一个示例:

template<class Self> // this class is defined only once
struct equally_comparable{
    friend bool operator!=(Self const& s1, Self const& s2){return !(s1==s2);}
};

此类可以反复用于在==!=之间强制执行一致的逻辑(并避免错误)

This class can used repeatedly to enforce consistent logic between == and != (and avoid errors)

struct A : equally_comparable<A>{ // 
    int value;
    A(int v) : value(v){}
    friend bool operator==(A const& a1, A const& a2){return a1.value == a2.value;}
};

int main(){

    A a1{4};
    A a2{4};
    assert(a1 == a2);
    A a3{5};
    assert(a1 != a3); // uses automatically generated operator !=
}

现在,我想更进一步,并拥有一个类似于equally_comparable的类并定义 other 函数.例如,如果定义了operator==,则定义operator!=(如上所述),反之亦然.

Now, I want to go one level further and have a class similar to equally_comparable and define the other function. For example if operator== is defined then define operator!= (like above), but also viceversa.

第一次天真尝试

template<class Self>
struct equally_comparable{
    friend bool operator!=(Self const& s1, Self const& s2){return !(s1==s2);}
    friend bool operator==(Self const& s1, Self const& s2){return !(s1!=s2);}
};

因为只需要在struct A中定义两个功能之一(operator==operator!=).但是,这很危险,因为如果忘记了在A中定义任何一个运算符,则将存在无限递归(以及运行时段错误).它看起来也很脆弱.

because only one of the two functions need to be defined in struct A (either operator== or operator!=). However it is dangerous because if one forget to define either operator in A there is an infinite recursion (and a runtime segfault). It also looks fragile.

是否可以对此进行改进,并在编译时检测到派生类中至少定义了一个?或更笼统地说,是否有一种通用的方法来生成一个生成丢失的运算符的类?(即,超越Boost.Operators的一步).

Is is possible to improve over this and detect that at least one is defined in the derived class at compile time? or more generally is there a generic way to have a class that generates the missing operators? (i.e. a step beyond Boost.Operators).

推荐答案

我将使用SFINAE以便在编译时检查比较器并相应地选择它们.

I would use SFINAE in order to check for comparators at compile time and choose them accordingly.

因此,它的工作方式如下:

so this would work as follows:

  • 在示例中在此处创建一个标记类(空),称为equal_comparable_tag
  • 您要利用附加重载的类应从此标签派生(因为继承后,该标签不会造成大小损失).
  • 附加比较器功能具有enable_if保护,因为与非模板版本匹配的功能是首选.警卫人员检查该类是否是从标记类派生的.
  • create a tagging class (empty) here in the example it is called equal_comparable_tag
  • classes you want to exploit the additional overloads should be derived from this tag (since it is inherited the tag doesn't incur a size penalty).
  • the additional comparator functions have an enable_if guard because of function matching the non templated version is preferred. The guard checks if the class is derived from the tagging class.
#include <type_traits>
#include <iostream>

struct equal_comparable_tag {};

struct tmp : public equal_comparable_tag {
    friend bool operator==(const tmp &, const tmp &) {
        std::cout << "baz";
        return false;
    }
};

struct tmp2 : public equal_comparable_tag {
    friend bool operator!=(const tmp2 &, const tmp2 &) {
        std::cout << "baz";
        return false;
    }
};

template<typename T>
typename std::enable_if<
std::is_base_of<equal_comparable_tag, T>::value,
bool
>::type
operator!=(const T &, const T&) {
    std::cout << "foo";
    return true;
}

template<typename T>
typename std::enable_if<
std::is_base_of<equal_comparable_tag, T>::value,
bool
>::type
operator==(const T &, const T&) {
    std::cout << "bar";
    return true;
}

int main(int argc, char** argv) {
    tmp a,b;
    tmp2 c,d;

    if (a != b) {} // foo
    if (a == b) {} // baz
    if (c != d) {} // baz
    if (c == d) {} // bar
}

注释

请注意,也可以执行自动功能签名检查(通常通过类型特征和功能指针进行查看,请参见这篇文章),但要复杂得多.如果要检查是否实现了两个功能,则这是必需的.另外请注意,您需要检查所有可能的组合.

Notes

Be aware, that automatic function signature checking can also be done (usually through type traits and function pointers See this article), but is considerable more complicated. This is required if you want to check if two functions are implemented. Be also aware that you need to check all possible combinations.

即:如果您有operator >operator ==,则必须检查:

i.e.: if you have operator > and operator == you'd have to check:

  • 具有成员函数>和成员函数==
  • 具有自由功能>,并且具有自由功能==
  • 具有自由函数>和成员函数==
  • 哈希成员函数>和自由函数==

并且如果有人使用隐式转换(例如:

and these checks fail if somebody uses implicit conversions e.g.:

struct tmp4 {
    tmp4(int) {
    }
    tmp4() {}
    operator int() const {
        return 10;
    }
    bool operator!=(int) const {
        std::cout << "baz";
        return false;
    }
};  
int main(int argc, char** argv) {
    tmp4 g, h;
    if (g != h) {} // compiles!
}

这篇关于C ++中的非常自动的运算符生成器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆