2016-05-16 1 views
0

Вот код:как избежать многих подобных перегрузок для C строк

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/л/GT/Г/GTE, а не только для равенства. Может быть, я уже что-то пропустил.

Есть ли способ не перечислять все возможные комбинации типов строк C?

Также C++ 98.

EDIT: >>here < < является онлайн демо с проблемой

+4

Ум, почему бы не просто перегрузить два аргумента 'const char *'? – Brian

+0

@Brian вызов с '' 'char *' '' и '' 'const char *' '' не делает трюк, если у меня есть перегрузка только с 2 '' 'const char *' '' - тогда шаблон получает вызов – onqtam

+0

Рассмотрите возможность использования 'operator ==' – stackptr

ответ

4

Распад тип массива указателю:

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; }; 

Проверьте, что тип не является указателем на (возможно const) char:

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 }; }; 

Теперь проверьте, что тип не является указателем или массив (возможно const) char:

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; } 
1
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 является truthy тогда и только тогда мы можем назвать 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...) 
); 
} 

сейчас, каковы шансы, что работает ? (Написано на телефоне, еще не составлено) Также не оптимально: много идеальной пересылки, некоторые из которых требуют делампинга.

+0

приятное усилие - что-то говорит мне, что там есть немного C++ 11 там :) – onqtam

Смежные вопросы