如果模板参数也提供比较运算符,则有条件地提供比较运算符的重载
Conditionally providing overload of comparizon operator if template parameter provides it too
我有一个模板 class
template <typename T>
class SometimesComparable
{
public:
T x1;
T x2;
// Other functionally provided unconditionally
// ...
// To be provided only if T provides operator<
// bool operator<(SometimesComparable const & other) const
// {
// return x1 < other.x1 && x2 < other.x2;
// }
};
当且仅当其模板参数也提供 bool operator<()
时才应提供 bool operator<()
我读过类似的 questions/answers 使用 SFINAE 但一定有一些我不明白的地方,因为我没有设法使这个想法适应这种情况。
模仿那些答案我有一个 class
template <typename T>
class HasLessThan
{
private:
typedef char YesType[1];
typedef char NoType[2];
template <typename C> static YesType& test( decltype(&C::operator<) );
template <typename C> static NoType& test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(YesType) };
};
通过其成员 value
使用其方法 test
来检测 class T
是否提供 operator<
.
里面SometimesComparable
class我在定义
typename std::enable_if<HasLessThan<T>::value, bool>::type
operator<(ConditionalMethodProvided &other)
{
return x1 < other.x1 && x2 < other.x2;
}
然后,为了测试,为了一个有效的用途,我有一个 class
class TypeWithLessThan
{
public:
int x;
TypeWithLessThan(int x) : x(x) {};
bool operator<(TypeWithLessThan &other) {return x < other.x;};
};
int main(int argc, char *argv[])
{
ConditionalMethodProvided C(TypeWithLessThan(2), TypeWithLessThan(3));
ConditionalMethodProvided D(TypeWithLessThan(5), TypeWithLessThan(7));
std::cout << (C < D) << std::endl;
return 0;
}
问题部分:这样就可以了。现在,我缺少的是如何实现
int main(int argc, char *argv[])
{
ConditionalMethodProvided C(2, 3);
ConditionalMethodProvided D(5, 7);
std::cout << (C < D) << std::endl;
return 0;
}
也编译成功。
我尝试添加到 SometimesComparable
好友方法
friend
typename std::enable_if<HasLessThan<T>::value, bool>::type
operator<(ConditionalMethodProvided & a1, ConditionalMethodProvided &a2)
{
return a1.x1 < a2.x1 && a1.x2 < a2.x2;
};
同时拥有第一个 operator<
和友元,会产生模棱两可的重载,没有它会导致 ConditionalMethodProvided<int, int>
的比较无法编译。
我希望 int
和 TypeWithLessThan
都能工作。
编辑:
单块代码
#include <iostream>
#include <type_traits>
template <typename T>
class HasLessThan
{
private:
typedef char YesType[1];
typedef char NoType[2];
template <typename C> static YesType& test( decltype(&C::operator<) );
template <typename C> static NoType& test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(YesType) };
};
template <typename T>
class ConditionalMethodProvided
{
public:
T x1;
T x2;
ConditionalMethodProvided(T&& a1, T&& a2) : x1(a1), x2(a2) {};
// This and the next method may not be needed at the same time.
typename std::enable_if<HasLessThan<T>::value, bool>::type
operator<(ConditionalMethodProvided &other)
{
return x1 < other.x1 && x2 < other.x2;
};
template <typename U,
std::enable_if_t<std::is_same_v<U, T>, bool> = true>
auto operator< (ConditionalMethodProvided<U> & oth)
-> decltype( std::declval<U>() < std::declval<U>(), bool{} )
{ return x1 < oth.x1 && x2 < oth.x2; }
};
class TypeWithLessThan
{
public:
int x;
TypeWithLessThan(int x) : x(x) {};
bool operator<(TypeWithLessThan &other) {return x < other.x;};
};
int main(int argc, char *argv[])
{
// The question is how to to make the next two types, int and TypewithLessThan both make the templated class ConditionalMethodProvided to provide the operator< method.
ConditionalMethodProvided C(TypeWithLessThan(2), TypeWithLessThan(3));
ConditionalMethodProvided D(TypeWithLessThan(5), TypeWithLessThan(7));
std::cout << (C < D) << std::endl;
ConditionalMethodProvided E(2,3);
ConditionalMethodProvided F(5,7);
std::cout << (E < F) << std::endl;
return 0;
}
下面呢?
template <typename T>
class SometimesComparable
{
public:
T x1;
T x2;
template <typename U,
std::enable_if_t<std::is_same_v<U, T>, bool> = true>
auto operator< (SometimesComparable<U> const & oth)
-> decltype( x1 < oth.x1, bool{} )
{ return x1 < oth.x1 && x2 < oth.x2; }
};
我的意思是...如果你想要 SFINAE enable/disable 一个方法,你必须把这个方法做成一个模板,所以
template <typename U>
bool operator< (SometimesComparable<U> const & oth)
{ /* something */ }
但我想你希望 U
和 T
是同一类型,所以你可以通过 std::enable_if_t
强加这个
template <typename U,
std::enable_if_t<std::is_same_v<U, T>, bool> = true>
bool operator< (SometimesComparable<U> const & oth)
{ /* something */ }
现在你必须启用 SFINAE 运算符 iff(当且仅当)你可以写 x1 < oth.x1
(当为 U
定义运算符时)所以,使用 auto
,尾随 return 类型和 decltype()
,你可以写
auto operator< (SometimesComparable<U> const & oth)
-> decltype( x1 < oth.x1, bool{} )
{ /* something */ }
或者如果您确定 x1 < oth.x1
给出 bool
值,也可以简单地 decltype( x1 < oth.x1 )
。
为了以后参考,你可以用C++20的概念写这个:
// To be provided only if T provides operator<
auto operator<(SometimesComparable const & other) const -> bool
requires requires(T a, T b) {
{a < b} -> bool;
}
{
return x1 < other.x1 && x2 < other.x2;
}
我有一个模板 class
template <typename T>
class SometimesComparable
{
public:
T x1;
T x2;
// Other functionally provided unconditionally
// ...
// To be provided only if T provides operator<
// bool operator<(SometimesComparable const & other) const
// {
// return x1 < other.x1 && x2 < other.x2;
// }
};
当且仅当其模板参数也提供 bool operator<()
bool operator<()
我读过类似的 questions/answers 使用 SFINAE 但一定有一些我不明白的地方,因为我没有设法使这个想法适应这种情况。
模仿那些答案我有一个 class
template <typename T>
class HasLessThan
{
private:
typedef char YesType[1];
typedef char NoType[2];
template <typename C> static YesType& test( decltype(&C::operator<) );
template <typename C> static NoType& test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(YesType) };
};
通过其成员 value
使用其方法 test
来检测 class T
是否提供 operator<
.
里面SometimesComparable
class我在定义
typename std::enable_if<HasLessThan<T>::value, bool>::type
operator<(ConditionalMethodProvided &other)
{
return x1 < other.x1 && x2 < other.x2;
}
然后,为了测试,为了一个有效的用途,我有一个 class
class TypeWithLessThan
{
public:
int x;
TypeWithLessThan(int x) : x(x) {};
bool operator<(TypeWithLessThan &other) {return x < other.x;};
};
int main(int argc, char *argv[])
{
ConditionalMethodProvided C(TypeWithLessThan(2), TypeWithLessThan(3));
ConditionalMethodProvided D(TypeWithLessThan(5), TypeWithLessThan(7));
std::cout << (C < D) << std::endl;
return 0;
}
问题部分:这样就可以了。现在,我缺少的是如何实现
int main(int argc, char *argv[])
{
ConditionalMethodProvided C(2, 3);
ConditionalMethodProvided D(5, 7);
std::cout << (C < D) << std::endl;
return 0;
}
也编译成功。
我尝试添加到 SometimesComparable
好友方法
friend
typename std::enable_if<HasLessThan<T>::value, bool>::type
operator<(ConditionalMethodProvided & a1, ConditionalMethodProvided &a2)
{
return a1.x1 < a2.x1 && a1.x2 < a2.x2;
};
同时拥有第一个 operator<
和友元,会产生模棱两可的重载,没有它会导致 ConditionalMethodProvided<int, int>
的比较无法编译。
我希望 int
和 TypeWithLessThan
都能工作。
编辑:
单块代码
#include <iostream>
#include <type_traits>
template <typename T>
class HasLessThan
{
private:
typedef char YesType[1];
typedef char NoType[2];
template <typename C> static YesType& test( decltype(&C::operator<) );
template <typename C> static NoType& test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(YesType) };
};
template <typename T>
class ConditionalMethodProvided
{
public:
T x1;
T x2;
ConditionalMethodProvided(T&& a1, T&& a2) : x1(a1), x2(a2) {};
// This and the next method may not be needed at the same time.
typename std::enable_if<HasLessThan<T>::value, bool>::type
operator<(ConditionalMethodProvided &other)
{
return x1 < other.x1 && x2 < other.x2;
};
template <typename U,
std::enable_if_t<std::is_same_v<U, T>, bool> = true>
auto operator< (ConditionalMethodProvided<U> & oth)
-> decltype( std::declval<U>() < std::declval<U>(), bool{} )
{ return x1 < oth.x1 && x2 < oth.x2; }
};
class TypeWithLessThan
{
public:
int x;
TypeWithLessThan(int x) : x(x) {};
bool operator<(TypeWithLessThan &other) {return x < other.x;};
};
int main(int argc, char *argv[])
{
// The question is how to to make the next two types, int and TypewithLessThan both make the templated class ConditionalMethodProvided to provide the operator< method.
ConditionalMethodProvided C(TypeWithLessThan(2), TypeWithLessThan(3));
ConditionalMethodProvided D(TypeWithLessThan(5), TypeWithLessThan(7));
std::cout << (C < D) << std::endl;
ConditionalMethodProvided E(2,3);
ConditionalMethodProvided F(5,7);
std::cout << (E < F) << std::endl;
return 0;
}
下面呢?
template <typename T>
class SometimesComparable
{
public:
T x1;
T x2;
template <typename U,
std::enable_if_t<std::is_same_v<U, T>, bool> = true>
auto operator< (SometimesComparable<U> const & oth)
-> decltype( x1 < oth.x1, bool{} )
{ return x1 < oth.x1 && x2 < oth.x2; }
};
我的意思是...如果你想要 SFINAE enable/disable 一个方法,你必须把这个方法做成一个模板,所以
template <typename U>
bool operator< (SometimesComparable<U> const & oth)
{ /* something */ }
但我想你希望 U
和 T
是同一类型,所以你可以通过 std::enable_if_t
template <typename U,
std::enable_if_t<std::is_same_v<U, T>, bool> = true>
bool operator< (SometimesComparable<U> const & oth)
{ /* something */ }
现在你必须启用 SFINAE 运算符 iff(当且仅当)你可以写 x1 < oth.x1
(当为 U
定义运算符时)所以,使用 auto
,尾随 return 类型和 decltype()
,你可以写
auto operator< (SometimesComparable<U> const & oth)
-> decltype( x1 < oth.x1, bool{} )
{ /* something */ }
或者如果您确定 x1 < oth.x1
给出 bool
值,也可以简单地 decltype( x1 < oth.x1 )
。
为了以后参考,你可以用C++20的概念写这个:
// To be provided only if T provides operator<
auto operator<(SometimesComparable const & other) const -> bool
requires requires(T a, T b) {
{a < b} -> bool;
}
{
return x1 < other.x1 && x2 < other.x2;
}