1

I have a function that takes in a parameter called arrayOfStrings defined as below:

const TCHAR* arrayOfStrings[] = { L"Test" };

Now I would like to convert strings to the type above, but I don't know how. This link provides a solution for converting string to tchar, but not const tchar*. This other link shows how to convert string to tchar*, but not const tchar*, and the memory allocation is a problem for me with this second solution. As you can probably tell, I am very new to c++, so any educational tips would be appreciated as well.

  • 1
    It's likely `TCHAR` not `tchar`. Since you initialize it with a wide-character arrays (the `L` prefix), you can only use a `std::wstring` because `TCHAR` is probably a typedef for `wchar_t`. – Holt Jun 28 '18 at 14:13
  • Thanks. You are right, it is TCHAR. Edited. – Navid Nazari Jun 28 '18 at 14:14
  • Is there a way to convert a std::wstring to const TCHAR*? – Navid Nazari Jun 28 '18 at 14:16
  • Yes, calling `wstring.c_str()` will return `const wchar_t*`. Though in MSVC you can switch between UNICODE and ANSI, that will affect the type of TCHAR. – rustyx Jun 28 '18 at 14:16
  • 1
    @NavidNazari If `TCHAR` is really a typedef for `wchar_t`, you can simply use `mywstring.c_str()` to get the underlying `const wchar_t*` array. The same thing can be done to convert `std::string` to `const char *`, but you have to know which type is `TCHAR` (`char` or `wchar_t`). – Holt Jun 28 '18 at 14:18
  • What you have there is not C++ per se. It's WinAPI which is a library written in C. Hence the whole shebang when it comes to character arrays. – Ron Jun 28 '18 at 14:22
  • @Ron Thanks for the clarification. – Navid Nazari Jun 28 '18 at 14:28
  • @rustyx neither std::string.c_str() nor std::wstring.c_str() are sutable conversions with my current settings. Would switching between ANSI and UNICODE help? – Navid Nazari Jun 28 '18 at 14:29
  • 3
    A *strong* recommendation is not to use `TCHAR` in new code, but decide on `wchar_t` and make your projects "Use Unicode character set". The duality of `TCHAR` being switchable between char/wchar_t hasn't been useful since the 1990's. – Bo Persson Jun 28 '18 at 14:32
  • @Holt TCHAR is of type wchar_t, but when I use .c_str on my wstring, I get the error: "cannot convert from const wchar_t* to const TCHAR**" – Navid Nazari Jun 28 '18 at 14:35
  • @BoPersson Thanks. That is good to know. – Navid Nazari Jun 28 '18 at 14:37

1 Answers1

1

A simple approach, which will work with all C++ standards, would be

 #include <string>

 #include <windows.h>    //   or whatever header you're using that specifies TCHAR

 int main()
 {
       std::string test("Hello");     //   string to be converted

       //   first, if you need a const TCHAR *

       std::basic_string<TCHAR> converted(test.begin(), test.end());

       const TCHAR *tchar = converted.c_str();

       //   use tchar as it is in the required form (const)

       //   second, if you need a TCHAR * (not const)

       std::vector<TCHAR> converted2(test.begin(), test.end());

       TCHAR *tchar2 = &converted2[0];

       // use tchar2 as it is of the required form (non-const).

 }

std::basic_string does not provide a means in all C++ standards to obtain a non-const pointer to its data, but std::vector does. (Assuming you don't use an explicit conversion to introduce or remove constness).

In C++17 and later, things are simpler: the basic_string::data() has both a const and non-const overload, which wasn't the case before the 2017 standard. Before C++11, the data in a basic_string was not guaranteed to be contiguous by the standard (even if implementations typically implemented things that way) but c_str() did provide the address of the first character of a contiguous array. The net effect is that, in C++17 and later, appropriate overloads of basic_string::data() or basic_string::c_str() can be used, without a need for cast to change constness, and without resorting to a vector (which has been guaranteed to have contiguous elements in all C++ standards).

Points to note in both cases

  1. The pointers (tchar and tchar2) are invalidated if their respective containers (converted or converted2) are resized or if they cease to exist. For example, don't use the data pointed to by tchar if converted has passed out of scope, since data tchar points at will no longer exist.
  2. It is simply undefined behaviour to use the pointers to run past the end (no magical resizing when using the pointers).
Peter
  • 35,646
  • 4
  • 32
  • 74
  • Thank you for the well explained answer! – Navid Nazari Jun 28 '18 at 15:03
  • RE _"`std::basic_string` does not provide a means to obtain a non-`const` pointer to its data"_ : This is not correct: you can use the [non-`const` overload of the `std::basic_string::data()` method](https://en.cppreference.com/w/cpp/string/basic_string/data) to modify the internal string content. – Mr.C64 Jun 28 '18 at 15:06
  • Continuing my comment above - In addition, even before the introduction of the non-`const` `data()` method overload in C++17, it was possible to write _in-place_ `std::basic_string`s using `&s[0]`. – Mr.C64 Jun 28 '18 at 15:14
  • @Mr.C64 - yeah, okay. Things changed in C++17. Before C++11 there also wasn't a guarantee that data in a `basic_string` be contiguous, or that `data()` and `c_str()` give the same pointers either. I'll update shortly to reflect – Peter Jun 28 '18 at 21:39