3

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!

Ðаn
  • 10,934
  • 11
  • 59
  • 95
  • 2
    How about `is_same_v || is_same_v`? – Aykhan Hagverdili Mar 02 '21 at 16:17
  • Ayxan has a practical answer, but the question as asked seems to suffer from some unsolvable problems. E.g. What if `wchar_t` is a typedef for `__wchar_t` ? `uint16_t` is definitely a typedef of some form (could be a `using`), and it might even be a typedef for `wchar_t` ! So even if you had a technically correct answer, it might not even be useful. – MSalters Mar 02 '21 at 17:04
  • 1
    @Ðаn: Sure, for just GCC you might find an an answer, but there you could just test the GCC version directly. I think GCC fixed it around 2.95.2 or so - it's been a type since C++98. – MSalters Mar 02 '21 at 17:22
  • Your example doesn't make much sense tbh. It's not like there is a specific encoding for `wchar_t`. Write a template, that takes any type, and depending on the size delegates the work to utf8, utf16 or utf32 specific routines. – Aykhan Hagverdili Mar 02 '21 at 18:17
  • I didn't mean to say `wchar_t` is utf8. I meant to say if you have a utf8 processing routine, you may as well support plain char. `wchar_t` is likely utf32 or utf16. Just do something like this https://gcc.godbolt.org/z/zfaf44 – Aykhan Hagverdili Mar 02 '21 at 18:33
  • 1
    @Ðаn No such thing across the board. The best you can hope for is some obscure template trick which won't play nicely with your preprocessor example. How about just testing for the version for major compilers (gcc, clang, msvc, icc, whatever else you support) and calling it a day? – Aykhan Hagverdili Mar 02 '21 at 18:43
  • `wchar_t` is a builtin type in all versions of Standard C++ , your compiler is non-conforming if otherwise – M.M Mar 02 '21 at 22:16
  • 2
    @M.M From the first sentence of this question I assume OP is working with a non-conforming ancient compiler. – Aykhan Hagverdili Mar 03 '21 at 04:56

1 Answers1

1

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 ...;
    }
}
Ðаn
  • 10,934
  • 11
  • 59
  • 95