检查类/结构是否有特定的操作符
Check if class/struct has a specific operator
我需要特殊化我的模板之一,并希望根据可用的操作符做到这一点。
我需要知道我是否可以做Foo == Bar
template<class T >
std::enable_if_t<has_equalOperator<T>::value> Compare( const T& other )
{
// can compare using ==
...
}
template<class T >
std::enable_if_t<!has_equalOperator<T>::value> Compare( const T& other )
{
// cannot compare use some other method
...
}
标准有类似的东西吗?如果不是,我该如何执行它?
这类特征类型几乎总是采用以下形式:
#include <utility>
#include <iostream>
#include <string>
template<class T, class Arg>
struct has_equals_impl
{
template<class U> static
auto test(const U* p)
-> decltype( /* the test is here */
(*p) == std::declval<Arg>(),
/* end of test */
void(), std::true_type());
static auto test(...) -> std::false_type;
using type = decltype(test((const T*)nullptr));
};
// this typedef ensures that the actual type is either std::true_type or std::false_type
template<class T, class Arg> using has_equals = typename has_equals_impl<T, Arg>::type;
int main()
{
// int == int? yes
std::cout << has_equals<int, int>() << std::endl;
// string == int? no
std::cout << has_equals<std::string, int>() << std::endl;
}
这是一套几乎完整的二进制运算符检查器,带有一些测试。
你应该了解大意。注意,我必须创建left_shift
和right_shift
函数对象,因为它们在标准库中已经不存在了。
#include <utility>
#include <iostream>
#include <string>
#include <algorithm>
#include <cassert>
template<class X, class Y, class Op>
struct op_valid_impl
{
template<class U, class L, class R>
static auto test(int) -> decltype(std::declval<U>()(std::declval<L>(), std::declval<R>()),
void(), std::true_type());
template<class U, class L, class R>
static auto test(...) -> std::false_type;
using type = decltype(test<Op, X, Y>(0));
};
template<class X, class Y, class Op> using op_valid = typename op_valid_impl<X, Y, Op>::type;
namespace notstd {
struct left_shift {
template <class L, class R>
constexpr auto operator()(L&& l, R&& r) const
noexcept(noexcept(std::forward<L>(l) << std::forward<R>(r)))
-> decltype(std::forward<L>(l) << std::forward<R>(r))
{
return std::forward<L>(l) << std::forward<R>(r);
}
};
struct right_shift {
template <class L, class R>
constexpr auto operator()(L&& l, R&& r) const
noexcept(noexcept(std::forward<L>(l) >> std::forward<R>(r)))
-> decltype(std::forward<L>(l) >> std::forward<R>(r))
{
return std::forward<L>(l) >> std::forward<R>(r);
}
};
}
template<class X, class Y> using has_equality = op_valid<X, Y, std::equal_to<>>;
template<class X, class Y> using has_inequality = op_valid<X, Y, std::not_equal_to<>>;
template<class X, class Y> using has_less_than = op_valid<X, Y, std::less<>>;
template<class X, class Y> using has_less_equal = op_valid<X, Y, std::less_equal<>>;
template<class X, class Y> using has_greater_than = op_valid<X, Y, std::greater<>>;
template<class X, class Y> using has_greater_equal = op_valid<X, Y, std::greater_equal<>>;
template<class X, class Y> using has_bit_xor = op_valid<X, Y, std::bit_xor<>>;
template<class X, class Y> using has_bit_or = op_valid<X, Y, std::bit_or<>>;
template<class X, class Y> using has_left_shift = op_valid<X, Y, notstd::left_shift>;
template<class X, class Y> using has_right_shift = op_valid<X, Y, notstd::right_shift>;
int main()
{
assert(( has_equality<int, int>() ));
assert((not has_equality<std::string&, int const&>()()));
assert((has_equality<std::string&, std::string const&>()()));
assert(( has_inequality<int, int>() ));
assert(( has_less_than<int, int>() ));
assert(( has_greater_than<int, int>() ));
assert(( has_left_shift<std::ostream&, int>() ));
assert(( has_left_shift<std::ostream&, int&>() ));
assert(( has_left_shift<std::ostream&, int const&>() ));
assert((not has_right_shift<std::istream&, int>()()));
assert((has_right_shift<std::istream&, int&>()()));
assert((not has_right_shift<std::istream&, int const&>()()));
}
在c++ 17中,可以简化为std::is_detected
:
typename <typename LHS, typename RHS>
using equal_t = decltype(std::declval<LHS>() == std::declval<RHS>());
template <typename T>
using has_equal = std::is_detected<equal_t, T, T>;
演示相关文章:
- 复制/移动操作符是否可以安全地用于实现复制/移动分配操作符
- sizeof操作符是否优先选择对象而不是类型
- gcc对vla的sizeof操作符的计算方式是否不同
- 是否可以重载*static_cast*操作符?
- 如果没有定义Move语义(Move构造函数和Move赋值操作符),编译器是否默认优化
- 在c++构造函数中使用new操作符是否正确?
- 是否基于其他操作符自动提供任何c++操作符重载
- c++ 11中常量表达式中是否允许使用逗号操作符?
- 是否需要重载类的强制转换操作符?
- 如何检查类型是否存在无参数操作符()
- 是否有方法为任何指针类型定义转换操作符
- 是否有办法为类的指针定义括号操作符?
- 是否可以继承赋值操作符?
- 间接操作符是否更改内存表示
- delete[]操作符是否适用于通过指针返回的动态分配的内存?
- 是否不可能手动调用c++操作符?
- 检测操作符是否存在并可在c++中调用(考虑static_assertions)
- 在设计Singleton模式时,赋值操作符是否需要私有?
- 如何检查下标操作符是否存在
- 如何查明函数模板中的赋值操作符T是否抛出异常