C++ SFINAE未正确禁用不明确的重载
我正在尝试构建一个更灵活的C++ SFINAE未正确禁用不明确的重载,c++,templates,c++17,overloading,sfinae,C++,Templates,C++17,Overloading,Sfinae,我正在尝试构建一个更灵活的std::equal_to,它可以在两种不同类型的T1和T2对象上调用,并且只需要定义T1::operator==(T2)或T2::operator==(T1)。我正在使用C++17。首先,我有一些结构测试是否定义了SomeType::operator==(OtherType): #包括 #包括 #包括 模板 定义的结构相等运算符:std::false_type{}; 模板 结构等式运算符已定义 :std::true_type{}; 我认为这是可行的-至少,用true
std::equal_to
,它可以在两种不同类型的T1
和T2
对象上调用,并且只需要定义T1::operator==(T2)
或T2::operator==(T1)
。我正在使用C++17。首先,我有一些结构测试是否定义了SomeType::operator==(OtherType)
:
#包括
#包括
#包括
模板
定义的结构相等运算符:std::false_type{};
模板
结构等式运算符已定义
:std::true_type{};
我认为这是可行的-至少,用true
或false
替换equalityoperator定义的equalityoperator的用法并不能解决问题。实际灵活的等于
:
template<class T1, class T2>
class FlexibleEqualsTo
{
private:
static constexpr bool cmpT1toT2 = EqualityOperatorDefined<T1, T2>::value;
static constexpr bool cmpT2toT1 = EqualityOperatorDefined<T2, T1>::value;
public:
template<class Dummy = T1>
constexpr bool operator()(const std::enable_if_t<cmpT1toT2, Dummy> & lhs, const T2& rhs)
{
return lhs == rhs;
}
template<class Dummy = T1>
constexpr bool operator()(const std::enable_if_t<cmpT2toT1 && !cmpT1toT2, Dummy> & lhs, const T2& rhs)
{
return rhs == lhs;
}
};
int main() {
FlexibleEqualsTo<int, int> foo;
}
模板
类FlexibleEqualsTo
{
私人:
静态constexpr bool cmpT1toT2=已定义的相等运算符::值;
静态constexpr bool cmpT2toT1=已定义的相等运算符::值;
公众:
模板
constexpr bool运算符()(const std::启用\u if\u t&lhs、const T2&rhs)
{
返回lhs==rhs;
}
模板
constexpr bool运算符()(const std::启用\u if\u t&lhs、const T2&rhs)
{
返回rhs==lhs;
}
};
int main(){
柔性等同于foo;
}
您可以找到完整的代码
然而,GCC和Clang都抱怨这里的错误重载。GCC告诉我:
<source>: In instantiation of 'class FlexibleEqualsTo<int, int>':
<source>:32:32: required from here
<source>:25:17: error: 'template<class Dummy> constexpr bool FlexibleEqualsTo<T1, T2>::operator()(std::enable_if_t<(FlexibleEqualsTo<T1, T2>::cmpT2toT1 && (! FlexibleEqualsTo<T1, T2>::cmpT1toT2)), Dummy>&, const T2&) [with Dummy = Dummy; T1 = int; T2 = int]' cannot be overloaded with 'template<class Dummy> constexpr bool FlexibleEqualsTo<T1, T2>::operator()(std::enable_if_t<FlexibleEqualsTo<T1, T2>::cmpT1toT2, Dummy>&, const T2&) [with Dummy = Dummy; T1 = int; T2 = int]'
25 | constexpr bool operator()(const std::enable_if_t<cmpT2toT1 && !cmpT1toT2, Dummy> & lhs, const T2& rhs)
| ^~~~~~~~
<source>:19:17: note: previous declaration 'template<class Dummy> constexpr bool FlexibleEqualsTo<T1, T2>::operator()(std::enable_if_t<FlexibleEqualsTo<T1, T2>::cmpT1toT2, Dummy>&, const T2&) [with Dummy = Dummy; T1 = int; T2 = int]'
19 | constexpr bool operator()(const std::enable_if_t<cmpT1toT2, Dummy> & lhs, const T2& rhs)
| ^~~~~~~~
:在“类FlexibleEqualsTo”的实例化中:
:32:32:从这里开始需要
:25:17:错误:'template constexpr bool FlexibleEqualsTo::operator()(std::enable_if_t&,const T2&)[with Dummy=Dummy;T1=int;T2=int]'不能用'template constexpr bool FlexibleEqualsTo::operator()(std::enable_if_t&,const T2&)[with Dummy=Dummy;T1=int;T2=int]'重载'
25 | constexpr bool运算符()(const std::启用_if_t&lhs、const T2&rhs)
| ^~~~~~~~
:19:17:注意:前面的声明“template constepr bool FlexibleEqualsTo::operator()(std::enable_if_t&,const T2&)[带Dummy=Dummy;T1=int;T2=int]”
19 | constexpr bool运算符()(const std::启用_if_t&lhs、const T2&rhs)
| ^~~~~~~~
如果std::enable\u中的两个布尔表达式中只有一个可以为真。因此,operator()
的另一个(在本例中是第二个)定义应该被删除,并且不应该存在重载问题
我想我避免了应用SFINAE的常见陷阱。两个函数模板都依赖于它们的模板参数
这里出了什么问题?您的操作符==
的SFINAE检测器被窃听。替换此项:
decltype(std::declval<FromT>() == std::declval<ToT>())
decltype(std::declval()==std::declval())
为此:
decltype(std::declval<FromT>() == std::declval<ToT>(), void())
decltype(std::declval()==std::declval(),void())
C++20中的FYIa==b
可以调用decltype(b)::operator==(decltype(a))
。这确实有效!谢谢但不知道为什么。因此,我假设您在这里使用序列运算符强制decltype(…)
中表达式的类型始终为空,即使未定义operator==
。为什么这是必要的?如果运算符==
未定义,模板替换是否应该失败,从而删除模板?@LukasBarth否,如果=
未定义,即使使用void()
也会失败。您的问题是类虚拟
是无效
,这与您的专业不匹配(预期虚拟
=布尔
)。啊,现在我明白了,谢谢。因此,另一种解决方案是将Dummy
的默认值更改为bool
,因为如果定义了运算符,这是decltype(std::declval()==std::declval())
的结果。谢谢@卢卡斯·巴特·耶普。