Search code examples
c++visual-c++typedefwchar-t

determine whether wchar_t is a built-in type or alias


Yes, wchar_t is supposed to be a built-in type in C++; unfortunately, that's not the case with some (very) old compilers. 😟

Is there a (compiler-specific, e.g., GCC/g++) way to determine whether wchar_t is a built-in type (keyword) or a typedef? The reason is to determine whether f(wchar_t) can be an overload; if wchar_t is a typedef, it will (very likely) be the same as f(uint16_t) or f(uint32_t).

Microsoft Visual C++ has _NATIVE_WCHAR_T_DEFINED so I can write:

#include <stdint.h>

#if defined(_MSC_VER)
   #define MY_PROJECT_wchar_t_is_built_in_ (_NATIVE_WCHAR_T_DEFINED == 1)
#else
   #define MY_PROJECT_wchar_t_is_built_in_ 1
#endif

void f(uint16_t ch_utf16) { /* UTF-16 processing */ }
void f(uint32_t ch_utf32) { /* UTF-32 processing */ }

#if MY_PROJECT_wchar_t_is_built_in_
   #include <type_traits>
   void f(whcar_t ch_)
   {
      using wchar_t_type = std::conditional<sizeof(wchar_t) == sizeof(uint32_t), uint32_t, uint16_t>::type;
      #ifdef _WIN32
      static_assert(sizeof(wchar_t_type) == sizeof(uint16_t), "wchar_t should be 16-bits on Windows.");
      #endif
      const auto ch = reinterpret_cast<wchar_t_type>(ch_);
      f(ch);
   }
#endif

Extensive TMP probably won't work (e.g., std::enable_if) ... as it's an old compiler causing the problem in the first place!


Solution

  • Ayxan Haqverdili's suggestion in comment of using a template with sizeof() solves my problem. (It also illustrates why sufficient context regarding "why?" is necessary.)

    My code is now:

    void f_(uint16_t ch_utf16) { /* UTF-16 processing */ }
    void f_(uint32_t ch_utf32) { /* UTF-32 processing */ }
    
    template<typename T>
    void f(T ch_)
    {
        static_assert(sizeof(T) == sizeof(wchar_t), "T should be wchar_t");
    
        if (sizeof(T) == sizeof(uint16_t))
        {
            const auto ch = reinterpret_cast<uint16_t>(ch_);
            f_(ch);
        }
        else if (sizeof(T) == sizeof(uint32_t))
        {
            const auto ch = reinterpret_cast<uint32_t>(ch_);
            f_(ch);
        }
        else
        {
            throw ...;
        }
    }