代码之家  ›  专栏  ›  技术社区  ›  Mordachai

C++字符串类型无关算法

  •  0
  • Mordachai  · 技术社区  · 15 年前

    我试图推导出一种编写字符串算法的技术,它真正独立于字符串的基本类型。

    背景:GetIndexOf和FindOneOf的原型是重载的或模板化的变体:

    int GetIndexOf(const char * pszInner, const char * pszString);
    const char * FindOneOf(const char * pszString, const char * pszSetOfChars);
    

    此问题在以下模板函数中出现:

    // return index of, or -1, the first occurrence of any given char in target
    template <typename T>
    inline int FindIndexOfOneOf(const T * str, const T * pszSearchChars)
    {
        return GetIndexOf(FindOneOf(str, pszSearchChars), str);
    }
    

    目标:
    1.我希望此代码适用于CStringT<>,常量char*,常量wchar\u t*(扩展到std::string应该很简单)
    2.我不想通过复制传递任何内容(仅通过常量和/或常量*)

    namespace details {
    
        template <typename T>
        struct char_type_of
        {
            // typedef T type; error for invalid types (i.e. anything for which there is not a specialization)
        };
    
        template <>
        struct char_type_of<const char *>
        {
            typedef char type;
        };
    
        template <>
        struct char_type_of<const wchar_t *>
        {
            typedef wchar_t type;
        };
    
        template <>
        struct char_type_of<CStringA>
        {
            typedef CStringA::XCHAR type;
        };
    
        template <>
        struct char_type_of<CStringW>
        {
            typedef CStringW::XCHAR type;
        };
    
    }
    
    #define CHARTYPEOF(T) typename details::char_type_of<T>::type
    

    允许:

    template <typename T>
    inline int FindIndexOfOneOf(T str, const CHARTYPEOF(T) * pszSearchChars)
    {
        return GetIndexOf(FindOneOf(str, pszSearchChars), str);
    }
    

    但是这种方法的问题是,当str是CStringT<>,是CStringT的副本<&燃气轮机;而不是引用它:因此我们有一个不必要的副本。

    试图将上述内容改写为:

    template <typename T>
    inline int FindIndexOfOneOf(T & str, const CHARTYPEOF(T) * pszSearchChars)
    {
        return GetIndexOf(FindOneOf(str, pszSearchChars), str);
    }
    

    使编译器(VS2008)无法生成FindIndexOfOneOf的正确实例<&燃气轮机;用于:

    FindIndexOfOneOf(_T("abc"), _T("def"));
        error C2893: Failed to specialize function template 'int FindIndexOfOneOf(T &,const details::char_type_of<T>::type *)'
        With the following template arguments: 'const char [4]'
    

    这是自模板引入以来我遇到的一个普遍问题(是的,我有那么老):基本上不可能构造一种方法来处理旧的C样式数组和新的基于类的实体(可能最好用const char[4]和CString<>)来突出显示)。

    STL/std库“解决”了这个问题(如果你真的可以称之为“解决”),方法是在任何地方使用成对的迭代器,而不是引用对象本身。我可以走这条路,除了它让我觉得很糟糕,而且我不想让我的代码到处都是两个参数,只要一个参数处理得当。

    基本上,我对一种方法感兴趣——比如使用某种严格的特性——这将允许我编写GetIndexOfOneOf<&燃气轮机;(和其他类似的模板函数),其中参数是字符串(不是一对(being,end)参数),然后根据该字符串参数类型生成的模板是正确的(或 常数* 或 常数CString<&燃气轮机& ).

    因此,问题是: 如何编写FindIndexOfOneOf<&燃气轮机;这样,其参数可以是以下任意一种,而无需创建基础参数的副本:

    2.CString-str;FindIndexofeof(str,_T(“def”));

    3.CString-str;findindexofeof(str,str);

    与此相关的线程将我引向了这一点:

    A better way to declare a char-type appropriate CString<>
    Templated string literals

    4 回复  |  直到 9 年前
        1
  •  2
  •   ronag    15 年前

    试试这个。

    #include <type_traits>
    inline int FindIndexOfOneOf(T& str, const typename char_type_of<typename std::decay<T>::type>::type* pszSearchChars)
    

    const char []
    

    但是你想要

    const char*
    

    您可以使用以下方法进行此转换。

    std::decay<T>::type 
    

    这个 documentation

    If is_array<U>::value is true, the modified-type type is remove_extent<U>::type *.
    
        2
  •  1
  •   j_random_hacker    15 年前

    你可以用Boost的 enable_if 和 type_traits 为此:

    #include <boost/type_traits.hpp>
    #include <boost/utility/enable_if.hpp>
    
    // Just for convenience
    using boost::enable_if;
    using boost::disable_if;
    using boost::is_same;
    
    // Version for C strings takes param #1 by value
    template <typename T>
    inline typename enable_if<is_same<T, const char*>, int>::type
    FindIndexOfOneOf(T str, const CHARTYPEOF(T) * pszSearchChars)
    {
        return GetIndexOf(FindOneOf(str, pszSearchChars), str);
    }
    
    // Version for other types takes param #1 by ref
    template <typename T>
    inline typename disable_if<is_same<T, const char*>, int>::type
    FindIndexOfOneOf(T& str, const CHARTYPEOF(T) * pszSearchChars)
    {
        return GetIndexOf(FindOneOf(str, pszSearchChars), str);
    }
    

    您可能应该扩展第一个案例来处理这两个问题 char 和 wchar_t 字符串,您可以使用 or_ from Boost's MPL library .

    我还建议将引用的版本改为常量引用。这只是避免了代码的两个独立版本的实例化(目前, T 将被推断为常量对象的常量类型,以及非常量对象的非常量类型;将参数类型更改为 T const& str 方法 T 将始终推断为非常量类型)。

        3
  •  1
  •   Edward Strange    15 年前

    根据您对迭代器的评论,您似乎没有充分考虑您可能拥有的选项。我对个人喜好无能为力,但话说回来。。。为了接受一个合理的解决方案,它不应该是一个难以克服的障碍,而应该加以权衡和平衡 从技术上讲

    template < typename Iter >
    void my_iter_fun(Iter start, Iter end)
    {
     ...
    }
    template < typename T >
    void my_string_interface(T str)
    {
      my_iter_fun(str.begin(), str.end());
    }
    template < typename T >
    void my_string_interface(T* chars)
    {
      my_iter_fun(chars, chars + strlen(chars));
    }
    
        4
  •  1
  •   ronag    15 年前

    如果您不想安装tr1,请选择我先前的答案。

    当第一个参数是引用时,添加以下模板专门化以覆盖推导的T类型。

    template<unsigned int N>
    struct char_type_of<const wchar_t[N]>
    { 
        typedef wchar_t type;
    };
    
    template<unsigned int N>
    struct char_type_of<const char[N]>
    { 
        typedef char type;
    };
    
    推荐文章