0

Most times that I forget the L prefix for a wchar_t literal, or that I put one by mistake for a char literal, it seems that compilation (g++) doesn't complain (no error, no warning) and that my program acts as intended.

for example

char cString[] = "Hello World!";
*std::strchr(cString, L'W') = L'w';
std::cout << cString << std::endl;

and

wchar_t cWideString[] = L"Hello World!";
*std::wcschr(cWideString, 'W') = 'w';
std::wcout << cWideString << std::endl;

both work.

Is it because, in this case, 'W' and 'w' are single-byte characters?

I'm interested, because I would like to use this on purpose, for functions like:

template<typename T> T* findNextSpace(T* str);

intended to be used for for T equal to char, const char, wchar_t, or const wchar_t. Would it be safe to use ' ' in the definition of such a function, for any character type T?

Or should I use something like (T) in order to cast the literal to the correct type?

EDIT: I know it makes a difference for char* and wchar_t*, but my question is not about string literals, it is about character literals.

  • 1
    Possible duplicate of [What exactly is the L prefix in C++?](https://stackoverflow.com/questions/13087219/what-exactly-is-the-l-prefix-in-c) –  Feb 06 '18 at 04:17

1 Answers1

0

Both cases fall under the rules for implicit conversions. Specifically the rules for integral conversions. The implicit conversion of char to whar_t should be well defined for all cases, as wchar_t is at least as wide as a char. Your compiler might warn you of the risk of data loss in the conversion from wchar_t to char, if the value of the wchar_t is (or can be in case the value isn't known at compile time) outside the range representable by char.

From my understanding the integer conversion rules applies to prvalue expressions of an integer type, characters are of integer type, and literals (except string literals) are prvalues, so this is why you see the behavior you see with the character literals, while you don't see it with string literals.

I don't have a version of the standard that I can look things up in, but I understand that cppreference is found to be a reasonable source of information. Hopefully it is accurate and I interpreted the rules correctly.

As for your question regarding finding the next space, you should probably split that into a separate question. With that said you should probably use std::isspace/std::iswspace (Unless you specifically only want ' '), and then have the compiler select the appropriate function based on T:

#include <type_traits>
#include <cwctype>
#include <cctype>

template <class T>
T* findNextSpace(T* str) {
    if constexpr(std::is_same_v<T, char>) {
        //Use std::isspace
    }
    else if(std::is_same_v<T, wchar_t>) {
        //Use std::iswspace
    }
    else {
        static_assert("Not implemented");
    }
}

In case your compiler doesn't support the features used here, you can implement a similar solution using template specialization:

#include <cwctype>
#include <cctype>

template <class T>
struct isspace_helper;

template <>
struct isspace_helper<char> {
    bool operator()(char c) const {
        return std::isspace(c);
    }
};

template <>
struct isspace_helper<wchar_t> {
    bool operator()(wchar_t c) const {
        return std::iswspace(c);
    }
};

Obviously you could also use this with std::string as well (Because most people would suggest you used std::string instead over char/wchar_t arrays unless you have a good reason not to):

#include <algorithm>
#include <string>

template <class CharT, class Traits, class Alloc>
auto findNextSpace(std::basic_string<CharT, Traits, Alloc>& str) {
    return std::find(str.begin(), str.end(), isspace_helper<CharT>{});
}

If your compiler doesn't support auto you can write std::basic_string<CharT, Traits, Alloc>::iterator instead. Then maybe provide an overloading accepting the string by const-reference for good measure.

Jacob
  • 3,626
  • 2
  • 20
  • 26
  • Finding the next space was just a simple example. Actually my current interest lies in a slightly more complex function, that I have already implemented for `char*`, `wchar_t*`, `std::string` and `std::wstring`, and which applies a set of syntactic rules to format the spacings of a text, so the non-necessity to write the prefix before `','`, `'"'`, `;` etc. will allow me to write much less code. As a beginner, it will be a good exercise to learn templates. I was started to suspect that character literals were just treated as integers when I managed to compile `int i = 'A'` and `int j =L'A'`. – Julien Dhondt Feb 06 '18 at 06:36
  • OK, I hope there was still some information in the aside from just the part about the rules. – Jacob Feb 06 '18 at 06:48