如何避免C字符串出现许多类似的重载

how to avoid many similar overloads for C strings

本文关键字:许多类 重载 何避免 字符串      更新时间:2023-10-16

以下是代码:

template <typename L, typename R> bool eq (const L& lhs, const R& rhs) { return lhs == rhs; }
template<int N> bool eq(char* lhs,           const char(&rhs)[N]) { return String(lhs).compare(rhs) == 0; }
template<int N> bool eq(const char(&lhs)[N], char* rhs)           { return String(lhs).compare(rhs) == 0; }
inline          bool eq(char* lhs,           char* rhs)           { return String(lhs).compare(rhs) == 0; }
inline          bool eq(const char* lhs,     const char* rhs)     { return String(lhs).compare(rhs) == 0; }
inline          bool eq(char* lhs,           const char* rhs)     { return String(lhs).compare(rhs) == 0; }
inline          bool eq(const char* lhs,     char*  rhs)          { return String(lhs).compare(rhs) == 0; }

我这样做是为了neq/lt/gt/lte/gte,而不仅仅是为了平等。也许我已经错过了什么。

有没有办法不列出C字符串类型的所有可能组合?

还有C++98。

编辑:>>此处<lt;是一个关于问题的在线演示

将数组类型衰减到指针:

template<class T>
struct decay_array { typedef T type; };
template<class T, size_t N>
struct decay_array<T[N]> { typedef T* type; };
template<class T>
struct decay_array<T[]> { typedef T* type; };

检查类型是否不是指向(可能是constchar:的指针

template<class T>
struct not_char_pointer { enum { value = true }; };
template<>
struct not_char_pointer<char*> { enum { value = false }; };
template<>
struct not_char_pointer<const char*> { enum { value = false }; };

现在检查类型是否不是指向(可能是constchar:的指针或数组

template<class T>
struct can_use_op : not_char_pointer<typename decay_array<T>::type> {};

重新实现std::enable_if:

template<bool, class = void>
struct enable_if {};
template<class T>
struct enable_if<true, T> { typedef T type; };

并使用它来约束您的模板:

template <typename L, typename R> 
typename enable_if<can_use_op<L>::value || can_use_op<R>::value, bool>::type 
eq (const L& lhs, const R& rhs) { return lhs == rhs; }

那么只要一个过载就足够了:

inline bool eq(const char* lhs, const char* rhs) { return String(lhs).compare(rhs) == 0; }
namespace details{
  template<template<class...>class Z,class,class...Ts>
  struct can_apply:std::false_type{};
  template<template<class...>class Z,class...Ts>
  struct can_apply<Z,std::void_t<Z<Ts...>>,Ts...>:std::true_type{};
}
template<template<class...>class Z,class...Ts>
using can_apply=details::can_apply<Z,void,Ts...>;

此测试模板是否可以应用于某些类型。

namespace strcmp{
  bool eq(const char*lhs, const char*rhs){/* body */}
}
template<class L, class R>
using str_eq_r=decltype(strcmp::eq(std::declval<L>(),std::declval<R>()));
template<class L, class R>
using can_str_eq=can_apply<str_eq_r,L,R>;

can_str_eq是真的,如果我们可以在它上面调用stdcmp::eq

namespace details {
  bool eq(const char* lhs, const char* rhs, std::true_type){
    return strcmp::eq(lhs,rhs);
  }
  template<class L,class R>
  bool eq(L const& l, R const&r,std::false_type){
    return l==r;
  }
}
template<class L,class R>
bool eq(L const& l, R const&r){
  return details::eq(l,r,can_str_eq<L const&,R const&>{});;
}

如果你喜欢的话,我们也可以使用static_if技巧来内联:

template<class L,class R>
bool eq(L const& l, R const&r){
  return static_if<can_str_eq>( l, r )(
    strcmp::eq,
    [](auto&& l, auto&& r){return l==r;}
  );
}

写入static_if:之后

template<class...Ts>
auto functor(Ts...ts){
  return [=](auto&& f){
    return f(ts...);
  };
}
namespace details{
  template<class Functor>
  auto switcher(std::true_type, Functor functor){
    return [=](auto&& t, auto&&){
      return functor(t);
    };
  }
  template<class Functor>
  auto switcher(std::false_type, Functor functor){
    return [=](auto&&, auto&& f){
      return functor(f);
    };
  }
}
template<template<class...>class test, class...Ts>
auto static_if(Ts...ts){
  return details::switcher(
    test<Ts...>{},
    functor(ts...)
  );
}

现在,可行的几率是多少?(写在电话上,尚未编译)也不是最佳的:需要大量完美的转发,其中一些需要de lamdaing。