【问题标题】:Disthinguish char and wchar_t in compile time在编译时区分 char 和 wchar_t
【发布时间】:2020-05-09 07:05:12
【问题描述】:

我有一个简单处理 TChar* 及其长度的模板类 simplestring。 TChar 既可以是 char 也可以是 wchar_t。 这是一个简单的左修剪方法,

simplestring<T> ltrim(const T* _s = nullptr) const
{
    const T* s = _s;
    if (s == nullptr)
    {
#if ( sizeof(T) == 1)
        s = " \t\r\n";
#else
        s = L" \t\r\n";
#endif
    }
    constexpr int len = tstrlen(s);
    find_first_not_of(s, len);
}

当 T 为 char 时,我希望 s 分配一个 char*,否则分配一个 wchar_t*。它不编译。 PS:我的项目支持C++17。

【问题讨论】:

    标签: c++ templates c++14


    【解决方案1】:

    另一种选择:

    template<typename CharT> foo(CharT const* &r);
    
    template<> foo(char const *&r) { r = " \t\r\n"; }
    template<> foo(wchar_t const *&r) { r = L" \t\r\n"; }
    

    【讨论】:

    • 我只是在想简单的函数重载(在调用位置推导类型)是否还不够......
    【解决方案2】:

    在 C++17 中你可以使用if constexpr:

    if constexpr (sizeof(T) == 1) // or (std::is_same_v<T, char>)
        s = " \t\r\n";
    else
        s = L" \t\r\n";
    

    【讨论】:

    【解决方案3】:

    在 C++14 中,引入了Variable templates

    因此,使用模板特化,可以为不同类型提供同名但不同值的变量。

    为了说明可能的解决方案,我制作了以下 MCVE:

    #include <iostream>
    
    template <typename T>
    constexpr const T *init;
    
    template <>
    constexpr const char *init<char> = "string";
    
    template <>
    constexpr const wchar_t *init<wchar_t> = L"wstring";
    
    template <typename T>
    struct simplestring {
      const T *str;
      simplestring(const T *str = init<T>): str(str) { }
    };
    
    int main()
    {
      simplestring<char> str;
      std::cout << "str: " << str.str << '\n';
      simplestring<wchar_t> wStr;
      std::wcout << "wStr: " << wStr.str << '\n';
    }
    

    输出:

    str: string
    wStr: wstring
    

    Live Demo on coliru


    变量模板为static consttemplate class simplestring的成员:

    #include <iostream>
    
    template <typename T>
    struct simplestring {
      static const T *init;
      const T *str;
      simplestring(const T *str = init): str(str) { }
    };
    
    template <>
    const char *simplestring<char>::init = "string";
    
    template <>
    const wchar_t *simplestring<wchar_t>::init = L"wstring";
    
    int main()
    {
      simplestring<char> str;
      std::cout << "str: " << str.str << '\n';
      simplestring<wchar_t> wStr;
      std::wcout << "wStr: " << wStr.str << '\n';
    }
    

    输出:

    str: string
    wStr: wstring
    

    Life Demo on coliru

    【讨论】:

    • 好主意!但是,init 只能是全局变量吗?不能成为简单字符串的成员吗?
    • @Zhang 我做了第二个样本。但是,other answer 实际上更接近您的预期并且更紧凑。 (我希望 Evg 在看到我的时会添加它。);-)
    • 我将您的两个答案作为混合答案发布。 (我并不是要窃取你的贡献:)我只是觉得这很棒。
    • 确实,@Evg's 最接近我的原始问题。但是我在我的代码中采用了你的。很难决定应该接受哪个作为这个问题的答案。 :(
    • @Zhang 这是一场公平的比赛,选择权在你。但是,如果您认为 Evg 的答案最接近您的期望 - 我会支持这一点。 ;-)
    【解决方案4】:

    结合 Scheff 和 Evg 的答案,我做了这个,

    template<typename T>
    struct simplestring
    {
        static const T *default_trim;// = nullptr;
    
    public:
        typedef std::basic_string<T> tstring;
        T* str = nullptr;
        unsigned int length = 0;
    
        void trim()
        {
            if constexpr(std::is_same<T, char>::value)
            {
                cout << "char";
                cout << default_trim;
            }
            else
            {
                cout << "wchar_t";
                wcout << default_trim;
            }
        }
    };
    
    template<>
    const char* simplestring<char>::default_trim = "hello \t\r\n";
    template<>
    const wchar_t* simplestring<wchar_t>::default_trim = L"hello \t\r\n";
    
    void test()
    {
        simplestring<char> s;
        s.trim();
        simplestring<wchar_t> s2;
        s2.trim();
    }
    

    感谢他们!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-31
      • 1970-01-01
      • 2010-10-03
      • 1970-01-01
      • 2023-03-19
      • 1970-01-01
      相关资源
      最近更新 更多