所以我想写一个自动的!=
:
template<typename U, typename T>
bool operator!=(U&& u, T&& t) {
return !( std::forward<U>(u) == std::forward<T>(t) );
}
但这是不礼貌的1。所以我写
// T() == U() is valid?
template<typename T, typename U, typename=void>
struct can_equal:std::false_type {};
template<typename T, typename U>
struct can_equal<
T,
U,
typename std::enable_if<
std::is_convertible<
decltype( std::declval<T>() == std::declval<U>() ),
bool
>::value
>::type
>: std::true_type {};
这是一个类型特征类,它说“是t == u
返回可转换为的类型的有效代码bool
”。
所以我改进了我的!=
:
template<typename U, typename T,
typename=typename std::enable_if<can_equal<T,U>::value>::type
>
bool operator!=(U&& u, T&& t) {
return !( std::forward<U>(u) == std::forward<T>(t) );
}
现在它只是一个有效的覆盖(如果==
存在)。可悲的是,它有点贪婪:
struct test {
};
bool operator==(const test&, const test&);
bool operator!=(const test&, const test&);
因为它会捕获几乎所有test() != test()
而不是上面!=
的调用。我认为这是不希望的——我宁愿调用显式而!=
不是自动转发==
和否定。
所以,我写了这个特质类:
template<typename T, typename U,typename=void>
struct can_not_equal // ... basically the same as can_equal, omitted
哪个测试是否T != U
有效。
然后我们增加!=
如下:
template<typename U, typename T,
typename=typename std::enable_if<
can_equal<T,U>::value
&& !can_not_equal<T,U>::value
>::type
>
bool operator!=(U&& u, T&& t) {
return !( std::forward<U>(u) == std::forward<T>(t) );
}
如果你解析它,它会说“这句话是假的”——operator!=
存在于 and 之间T
,U
当且仅当operator!=
且不存在于T
and之间U
。
毫不奇怪,我测试过的每个编译器都会在输入这个时出现段错误。(clang 3.2,gcc 4.8 4.7.2 英特尔 13.0.1)。 我怀疑我正在做的事情是非法的,但我很想看到标准参考。(编辑:我所做的是非法的,因为它会导致无限递归模板扩展,因为确定我的!=
应用是否需要我们检查我的!=
应用。评论中链接的版本带有#if 1
,给出了一个合理的错误)。
但我的问题是:有没有一种方法可以说服我基于 SFINAE 的覆盖在决定它是否应该失败时忽略“自身”,或者以某种方式摆脱自我引用问题?或者降低我的优先级operator!=
足够低以便任何显式!=
获胜,即使它不是那么好的匹配?
不检查“!=
不存在”的那个工作得相当好,但还不足以让我像将其注入全局命名空间那样不礼貌。
目标是,一旦我的“魔法”被引入,任何可以在没有我的“魔法”的情况下编译的代码都会!=
做同样的事情。!=
当且仅当!=
否则无效并且 bool r = !(a==b)
格式正确时,我的“魔术”才!=
起作用。
脚注1:如果你创建一个template<typename U, typename T> bool operator!=(U&& u, T&& t)
,SFINAE 会认为每一对类型!=
在它们之间都有一个有效的。然后,当您尝试实际调用时!=
,它会被实例化,并且无法编译。最重要的是,你踩着bool operator!=( const foo&, const foo& )
函数,因为你更适合foo() != foo()
and foo a, b; a != b;
。我认为这两种做法都是不礼貌的。