Instantiate a basic_string with a text value independent of char or wchar_t

R

Ryan

I have a template method that extracts the file name from a string. The string can either be a char or wchar_t type. I would like to define the value "/\\" as the constructor value of my basic_string<T>. I'm currently having to define the value "/\\" as a basic_string<char> and using its iterators as an input for the basic_string<T>. Is it possible to use "/\\" value directly in the basic_string<T>?

Ryan

#include <string>
#include <iostream>

template<typename T>
std::basic_string<T> getFileName(
std::basic_string<T> const& pathAndFileName) {
std::basic_string<char> pattern("/\\");

return pathAndFileName.substr(
pathAndFileName.find_last_of(
std::basic_string<T>(pattern.begin(), pattern.end())) + 1);
}

int main(int, char const *[]) {
std::basic_string<char> string1("sub\\directory\\file.txt");
std::string result1 = getFileName(string1);
std::cout << result1 << std::endl;


std::basic_string<wchar_t> string2(L"sub\\directory\\file.txt");
std::basic_string<wchar_t> result2 = getFileName(string2);
std::wcout << result2 << std::endl;

return 0;
}
 
V

Victor Bazarov

I have a template method that extracts the file name from a string.
The string can either be a char or wchar_t type. I would like to define
the value "/\\" as the constructor value of my basic_string<T>. I'm
currently having to define the value "/\\" as a basic_string<char> and
using its iterators as an input for the basic_string said:

Not sure what you're asking, would that work:

template<class T> basic_string<T> getPattern();

template<> basic_string<char> getPattern<char>()
{
return "/\\";
}

template<> basic_string<wchar_t> getPattern<wchar_t>()
{
return L"/\\";
}

, and then use the one based on the T type:

...
.find_last_of(getPattern<T>())

in your 'getFileName'? The proper one should be picked up. Or you
could simply overload it based on the 'T' itself:

basic_string<char> getPattern(char) { return "/\\"; }
basic_string<wchar_t> getPattern(wchar_t) { return L"/\\"; }

and use

.find_last_of(getPattern(T(0)))

?
#include <string>
#include <iostream>

template<typename T>
std::basic_string<T> getFileName(
std::basic_string<T> const& pathAndFileName) {
std::basic_string<char> pattern("/\\");

return pathAndFileName.substr(
pathAndFileName.find_last_of(
std::basic_string<T>(pattern.begin(), pattern.end())) + 1);
}

int main(int, char const *[]) {
std::basic_string<char> string1("sub\\directory\\file.txt");
std::string result1 = getFileName(string1);
std::cout << result1 << std::endl;


std::basic_string<wchar_t> string2(L"sub\\directory\\file.txt");
std::basic_string<wchar_t> result2 = getFileName(string2);
std::wcout << result2 << std::endl;

return 0;
}
 
R

Ryan

Not sure what you're asking, would that work:
template<class T> basic_string<T> getPattern();

template<> basic_string<char> getPattern<char>()
{
return "/\\";
}

template<> basic_string<wchar_t> getPattern<wchar_t>()
{
return L"/\\";
}

There are two problem with creating the 'getPattern' methods.

1. There are two methods that do the equivalent of the following two lines:
std::basic_string<char> pattern("/\\");
std::basic_string<T> value(pattern.begin(), pattern.end());

The two lines seems like a simpler approach than creating additional methods.

2. This only covers the use cases for char and wchar_t. If a different type is passed to the template methods than it doesn't know what 'getPattern' method to call. I realize I stated the string can either be char or wchar_t. I'm wanting to find a solution that would extend to other cases though.


In short I want to do the following:

std::basic_string<T> value("/\\");

How do I define "/\\" so that it will work for all types of T without defining it as a char first and then passing it as an iterator?

Ryan
 
N

Nobody

In short I want to do the following:

std::basic_string<T> value("/\\");

How do I define "/\\" so that it will work for all types of T without
defining it as a char first and then passing it as an iterator?

You can't. Only one of the std::basic_string constructors is a
template, and that takes a pair of iterators. With the exception of the
default constructor, the others all take arguments which depend upon the
character type.

Also, I believe that your approach of using the iterator-based constructor
is non-portable. It assumes that converting a char to a wchar_t via
integral conversion produces the correct result (i.e. that e.g.
static_cast<wchar_t>('/') == L'/'), and I don't think that this is
guaranteed by the standard. [cpp.predefined/2] says:

__STDC_MB_MIGHT_NEQ_WC__
The integer constant 1, intended to indicate that, in the encoding for
wchar_t, a member of the basic character set need not have a code value
equal to its value when used as the lone character in an ordinary
character literal.

The "right" way to convert between narrow and wide strings is with a
locale's codecvt facet, but that has enough complexities that it's
probably not the sort of thing which should be done implicitly.
 
R

Ryan

You can't. Only one of the std::basic_string constructors is a
template, and that takes a pair of iterators. With the exception of the
default constructor, the others all take arguments which depend upon the
character type.

That's too bad.
The "right" way to convert between narrow and wide strings is with a
locale's codecvt facet, but that has enough complexities that it's
probably not the sort of thing which should be done implicitly.

If that is the only "right" way to do it, I'll stick with the non-portable way for now. If I run into problems, I'll revisit the issue.

Thank you for your insight.

Ryan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top