Looking for a more elegant solution to this meta-programming bit

Hi,

I have what I want in terms of functionality (I can pass a string or wstring and the function template quotes the string or wstring with the appropriate quote_char). However, I don't like the style of my solution, I am sure there must be a more elegant approach.

This is my current first solution:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
	template<typename Element>
	struct get_quote
	{
		static constexpr void const* chars[2] = {"\"", L"\"" };
		static constexpr Element const * quote_char = reinterpret_cast<Element const *>( chars[sizeof(Element) - 1]);
	};


	template<typename Element >
	inline std::basic_string<Element> quote(const std::basic_string<Element>& str)
	{
		constexpr Element const* quoted_char = get_quote<Element>::quote_char;

		std::basic_string<Element> quoted = quoted_char;
		quoted += str;
		quoted += quoted_char;
		return quoted;
	}


Any ideas greatly appreciated!

Juan Dent
Does std::quoted work for you? ( http://en.cppreference.com/w/cpp/io/manip/quoted )
Or will the extra escaping cause problems?
Last edited on
To begin with, it doesn't compile:


prog.cc:8:36: error: constexpr variable 'quote_char' must be initialized by a constant expression
                static constexpr Element const * quote_char = reinterpret_cast<Element const *>( chars[sizeof(Element) - 1]);
                                                 ^            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prog.cc:15:62: note: in instantiation of static data member 'get_quote<char>::quote_char' requested here
                constexpr Element const* quoted_char = get_quote<Element>::quote_char;
                                                                           ^
prog.cc:25:18: note: in instantiation of function template specialization 'quote<char>' requested here
    std::cout << quote(std::string("abc")) << '\n';
                 ^
prog.cc:8:49: note: reinterpret_cast is not allowed in a constant expression
                static constexpr Element const * quote_char = reinterpret_cast<Element const *>( chars[sizeof(Element) - 1]);


Second, your quote_char is not a char, it's a string. Let's do chars, here's some old-school template specialization for you:

1
2
3
4
5
6
7
8
9
10
11
template<class CharT> struct my_traits;
template<> struct my_traits<char> { static const char quote_char = '"'; };
template<> struct my_traits<char16_t> { static const char16_t quote_char = u'"'; };
template<> struct my_traits<char32_t> { static const char32_t quote_char = U'"'; };
template<> struct my_traits<wchar_t> { static const wchar_t quote_char = L'"'; };

template<class CharT>
std::basic_string<CharT> quote(const std::basic_string<CharT>& str)
{
    return my_traits<CharT>::quote_char + str + my_traits<CharT>::quote_char;
}


... pass a string or wstring and the function template quotes the string or wstring with the appropriate quote_char ...

if this is indeed the entire issue then why not just plain function overloading? Is there any need for TMP?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# include <iostream>
# include <string>
# include <iomanip>

auto quote (const std::string& str)
{
    std::cout <<  std::string ("\"") + str + std::string("\"\n");
}
auto quote (const std::wstring& str)
{
    std::wcout << std::wstring(L"\"") + str + std::wstring(L"\"\n");
}

int main()
{
    std::string input_string = "helloWorldString";
    quote(input_string);
    std::wstring input_wstring = L"helloWorldWstring";
    quote(input_wstring);
}

http://coliru.stacked-crooked.com/a/270dc6d5ef279e20
Last edited on
but it does compile (at least in VC 2017 v 15.3.0).
And quote_char is neither a string nor a character: it is a pointer to a char[] or wchar[].
I like to use TMP and after looking at other solutions (those posted here) I kind of like mine best.

But I was looking for a TMP solution that is better than mine: better in this sense (cleaner, more efficient, ...)

BTW, for some reason std::quoted does not work!

Regards,
Juan
(cleaner, more efficient, ...)

define "cleaner"? if anything, the use of reintepret_cast, pointer to void, and assumption that sizeof(wchar_t)==2 (only true on Windows because it's stuck in 1995) don't strike me as "clean". And the unnecessary string literals sitting in static memory.
Last edited on
> BTW, for some reason std::quoted does not work!

#include <iomanip>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <iomanip>
#include <string>

int main()
{
    const std::string str_out = "abcd\"efgh\"ijkl" ;
    std::cout << std::quoted(str_out) << '\n' //           "abcd\"efgh\"ijkl"
              << std::quoted( str_out, '\'' ) << '\n' ; // 'abcd"efgh"ijkl'
    
    
    std::string str_in ;
    std::cin >> std::quoted(str_in) ; // enter:          "He said \"Hello Juan Dent!\" and waved."  
    std::cout << str_in << '\n' //                        He said "Hello Juan Dent!" and waved.
              << std::quoted( str_in, '%' )  << '\n'  // %He said "Hello Juan Dent!" and waved.% 
              << std::quoted( str_in, '"' ) << '\n' ; // "He said \"Hello Juan Dent!\" and waved."
}

http://rextester.com/HYUCDR25760
PS, if you want a hip modern way of mapping types to constants, check out boost:

1
2
3
4
5
6
7
8
9
10
11
12
constexpr auto m = hana::make_map(
    hana::make_pair(hana::type_c<char>, '"'),
    hana::make_pair(hana::type_c<char16_t>, u'"'),
    hana::make_pair(hana::type_c<char32_t>, U'"'),
    hana::make_pair(hana::type_c<wchar_t>, L'"')
);

template<class CharT>
std::basic_string<CharT> quote(const std::basic_string<CharT>& str)
{
    return m[hana::type_c<CharT>] + str + m[hana::type_c<CharT>];
}
Thank you guys!

I was looking for the solution provided by Cubbi!

Regards,
Juan Dent
Topic archived. No new replies allowed.