Croper 发表于 2020-1-16 21:57:52

C++有没有办法禁止两个类型通过第三方类型调用==运算?

本帖最后由 Croper 于 2020-1-17 01:03 编辑

最近,我正在尝试自行实现一个variant类型,
在实现operator==的重载时,我希望能实现如果variant的两个底层类型之间如果能够调用==运算符时,
能调用==运算符,不能时,输出false,就像下面这样的效果

    variant(1)==variant("hello world") //false
    variant(1)==variant(3.14) //false
    variant(1)==variant(1.0)//true

为了判断两个类型是否能调用==运算符,我使用了这段代码
检测两个类型是否能进行"=="运算。

template <typename T1, typename T2>
struct CanEqual {
private:
        template <typename = decltype(declval<T1>() == declval<T2>())>
        constexpr static auto answer(int) { return true; };
        constexpr static auto answer(...) { return false; };
public:
        constexpr operator bool() {
                return answer(0);
        }
};


本来一切实现得很完美,两个底层类型不能==运算就输出false,能就输出==运算的结果。

但是调式时,发现在variant实现operator==运算后,两个底层类型在判断能否进行==运算时,会将他们俩都转换成varaint。

然后就死循环了。。。

这让我很纠结,因为我并不想把构造函数声明成explicit的

参考了下boost库,发现boost库下的variant根本没考虑这一点,variant(1)==variant(1.0)的结果是false的。

所以,这个问题有没有什么好点的解决方法?

人造人 发表于 2020-1-16 22:40:10

把你现在的代码发上来,我调试一下
注意是现在的代码,然后加上注释,尽量说明问题,突出问题,这样更有利于我调试

Croper 发表于 2020-1-16 23:28:46

完整代码快千行了,我丢在guthub的:https://github.com/CroperShen/variant

我还是弄个简化版的把- -

Croper 发表于 2020-1-17 00:44:47

首先看这一段代码:
你可以单步调试跟踪,不能调用==的变量和能调用==的变量进入的分支是不同的:
template <typename T1,typename T2,typename=decltype(declval<T1>()==declval<T2>())>
bool Equal(const T1& t1, const T2& t2) {          //能调用==的变量进入这个分支
        return t1 == t2;
}
bool Equal(...) {            //不能调用==的变量进入这个分支
        return false;
}


int main() {
        bool a = Equal(1, 1.000);
        bool b = Equal(0, string());
        system("pause");
}

Croper 发表于 2020-1-17 00:50:56

.....我想我解决这个问题了。。。

Croper 发表于 2020-1-17 00:55:03

本帖最后由 Croper 于 2020-1-17 00:56 编辑

我把刚才的说完把。。现在在这个代码里加入一个类,
拥有int和string的构造函数,并且重载了operator==struct A {
        A(int) {};
        A(string) {};
};
bool operator ==(const A&, const A&)
{
        return true;
};
template <typename T1,typename T2,typename=decltype(declval<T1>()==declval<T2>())>
bool Equal(const T1& t1, const T2& t2) {          //能调用==的变量进入这个分支
        return t1 == t2;
}
bool Equal(...) {            //不能调用==的变量进入这个分支
        return false;
}


int main() {
        bool a = Equal(1, 1.000);
        bool b = Equal(0, string());
        system("pause");
}

这个时候Equal(0,string())就变成true了。。因为Erqual和string都转换成了A,单步调式可以看出来的。

Croper 发表于 2020-1-17 00:58:10

解决这个问题只要把operator==写成成员函数就好
struct A {
        A(int) {};
        A(string) {};
        bool operator ==(const A&) { return true; };
};
这样就不会出现全局的转换了。。

Croper 发表于 2020-1-17 01:02:28

我之前写出来是因为写成成员函数的话,
vecotr<A>的相等就不能直接使用==了struct A {
      A(int) {};
      A(string) {};
      bool operator ==(const A&) { return true; };
...
vector<A>()==vector<A>(); //编译不通过:未能找到匹配的重载函数。。
};

而写出来就可以了struct A {
        A(int) {};
        A(string) {};
};

bool operator ==(const A&,const A&) { return true; };
...
vector<A>()==vector<A>() ;//能够编译通过。

Croper 发表于 2020-1-17 01:03:19

本帖最后由 Croper 于 2020-1-17 01:07 编辑

我以前一直认为写在成员函数里的运算符重载和写在外面的运算符重载没多大区别。。。没想到区别这么大。。

C++的坑真心多。。。

相比起这个问题,我还是自己写vector相等的判定把。。。毕竟重载个equal_to就够,简单得多。。
页: [1]
查看完整版本: C++有没有办法禁止两个类型通过第三方类型调用==运算?