Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ SFINAE未正确禁用不明确的重载_C++_Templates_C++17_Overloading_Sfinae - Fatal编程技术网

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中的FYI
a==b
可以调用
decltype(b)::operator==(decltype(a))
。这确实有效!谢谢但不知道为什么。因此,我假设您在这里使用序列运算符强制
decltype(…)
中表达式的类型始终为空,即使未定义
operator==
。为什么这是必要的?如果
运算符==
未定义,模板替换是否应该失败,从而删除模板?@LukasBarth否,如果
=
未定义,即使使用
void()
也会失败。您的问题是
类虚拟
无效
,这与您的专业不匹配(预期
虚拟
=
布尔
)。啊,现在我明白了,谢谢。因此,另一种解决方案是将
Dummy
的默认值更改为
bool
,因为如果定义了运算符,这是
decltype(std::declval()==std::declval())
的结果。谢谢@卢卡斯·巴特·耶普。