- C++11
- msvc2015u3,gcc5.4,clang3.8.0
I've used a bit another approach with template specialization to equalize deduction preorities between not template function with const char *
argument and template function with const char (&)[S]
argument, plus string character type tagging together with T &&
:
#include <string>
#include <cstdio>
#include <type_traits>
struct tag_string{};
struct tag_wstring{};
template <typename t_elem, typename t_traits, typename t_alloc>
inline constexpr const t_elem * get_c_str(const std::basic_string<t_elem, t_traits, t_alloc> & str)
{
return str.c_str();
}
template <typename CharT>
inline constexpr CharT * get_c_str(CharT * str)
{
return str;
}
namespace detail {
template <typename T>
void _foo(T && s, tag_string)
{
// to check on convertion from string type
static_assert(std::is_convertible<T, std::string>::value, "must be convertible to a std::string type");
// implementation for char
printf("%s: _foo(T &&, tag_string)\n\n", get_c_str(s));
}
template <typename T>
void _foo(T && s, tag_wstring)
{
// to check on convertion from string type
static_assert(std::is_convertible<T, std::wstring>::value, "must be convertible to a std::wstring type");
// implementation for wchar_t
printf("%ls: _foo(T &&, tag_wstring)\n\n", get_c_str(s));
}
}
// for rvalues
void foo(std::string && s)
{
puts("foo(std::string &&)");
detail::_foo(s, tag_string{});
}
// for lvalues
void foo(const std::string & s)
{
puts("foo(const std::string &)");
detail::_foo(s, tag_string{});
}
// for lvalue/rvalue character arrays with compile time size
template <size_t S>
void foo(const char (& s)[S])
{
puts("foo(const char (&)[])");
detail::_foo(s, tag_string{});
}
// for character pointers w/o compile time size (can be with second parameter of string runtime size)
template <typename T>
void foo(const T * const & s);
// through template specialization to equalize priorities over function overloading deduction
template<>
void foo(const char * const & s)
{
puts("foo(const char * const &)");
detail::_foo(s, tag_string{});
}
'
int main()
{
foo("111");
char a[] = "222";
foo(a);
const char a2[] = "333";
foo(a2);
char * b = a;
foo(b);
const char * b2 = "555";
foo(b2);
foo({'6', '6', '6', '\0'});
foo(std::string{"777"});
std::string s = "888";
foo(s);
}
Output:
foo(const char (&)[])
111: _foo(T &&, tag_string)
foo(const char (&)[])
222: _foo(T &&, tag_string)
foo(const char (&)[])
333: _foo(T &&, tag_string)
foo(const char * const &)
222: _foo(T &&, tag_string)
foo(const char * const &)
555: _foo(T &&, tag_string)
foo(const char (&)[])
666: _foo(T &&, tag_string)
foo(std::string &&)
777: _foo(T &&, tag_string)
foo(const std::string &)
888: _foo(T &&, tag_string)
https://godbolt.org/z/hgs7Vh
https://rextester.com/GJZ41642