鱼C论坛

 找回密码
 立即注册
查看: 1389|回复: 8

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

[复制链接]
发表于 2020-1-16 21:57:52 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 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的。

所以,这个问题有没有什么好点的解决方法?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-1-16 22:40:10 | 显示全部楼层
把你现在的代码发上来,我调试一下
注意是现在的代码,然后加上注释,尽量说明问题,突出问题,这样更有利于我调试
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-1-16 23:28:46 | 显示全部楼层
完整代码快千行了,我丢在guthub的:https://github.com/CroperShen/variant

我还是弄个简化版的把- -
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 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");
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-1-17 00:50:56 | 显示全部楼层
.....我想我解决这个问题了。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 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,单步调式可以看出来的。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-1-17 00:58:10 | 显示全部楼层
解决这个问题只要把operator==写成成员函数就好
struct A {
        A(int) {};
        A(string) {};
        bool operator ==(const A&) { return true; };
};
这样就不会出现全局的转换了。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 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>() ;//能够编译通过。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-1-17 01:03:19 | 显示全部楼层
本帖最后由 Croper 于 2020-1-17 01:07 编辑

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

C++的坑真心多。。。

相比起这个问题,我还是自己写vector相等的判定把。。。毕竟重载个equal_to就够,简单得多。。

评分

参与人数 1荣誉 +5 鱼币 +5 贡献 +3 收起 理由
人造人 + 5 + 5 + 3 鱼C有你更精彩^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-1-16 07:58

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表