形質のこの種のは、ほとんどの場合、以下の形式をとる入力します。ここでは
#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
関数オブジェクトは標準ライブラリには存在しないので、作成する必要があります。 C++ 17では
#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&>()()));
}
あなたはここで見ていますか? http://stackoverflow.com/questions/6534041/how-to-check-whether-operator-exists – Hayt
いいえ、私はありませんでした、リンクのおかげで。 –