Zhang
Zhang

Reputation: 3356

Disthinguish char and wchar_t in compile time

I have a template class simplestring which simplely handles TChar* and its length. TChar can be both char and wchar_t. Here is a simple left trim method,

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

I want s would be assigned a char* when T is char and otherwise be assigned a wchar_t*. It doesn't compile. PS: My project supports C++17.

Upvotes: 1

Views: 260

Answers (4)

M.M
M.M

Reputation: 141628

Yet another option:

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

Upvotes: 2

Zhang
Zhang

Reputation: 3356

Combined answers from Scheff and Evg, I made this one,

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

Thanks to them!

Upvotes: 0

Scheff&#39;s Cat
Scheff&#39;s Cat

Reputation: 20141

With C++14, Variable templates have been introduced.

So, using template specialization, it is possible to provide a variable with same name but different values for different types.

To illustrate a possible solutionh, I made the following 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';
}

Output:

str: string
wStr: wstring

Live Demo on coliru


The variable template as static const member of template 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';
}

Output:

str: string
wStr: wstring

Life Demo on coliru

Upvotes: 1

Evg
Evg

Reputation: 26342

In C++17 you can use if constexpr:

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

Upvotes: 1

Related Questions