Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

const char array (c style string) template specialization

Tags:

c++

templates

I want to be able to specialize based on a constant c style string. The problem is that when I call my templatized function the type is const char[N] where 'N' is the size of the string +1 (null character). How can I specialize for all c-style strings?

The following code displays the problem. You can see the specialization for const char [15] gets matched for "const char [15]" but for "const char[5]" it goes to Generic.

Is there any way to do this?

template <typename T>
struct Test {
  static const char* type() { return "Generic"; }
};

template <>
struct Test<const char*> {
  static const char* type() { return "const char*"; }
};

template <>
struct Test<const char[]> {
  static const char* type() { return "const char[]"; }
};

template <>
struct Test<const char[15]> {
  static const char* type() { return "const char[15]"; }
};

template <>
struct Test<char*> {
  static const char* type() { return "char*"; }
};

template <>
struct Test<char[]> {
  static const char* type() { return "char[]"; }
};

template <typename T>
void PrintType(const T& expected) {
  std::cerr << expected << " type " << Test<T>::type() << std::endl;
}
int main(int argc, char* argv[]) {
  const char* tmp = "const char*";
  PrintType(tmp);
  PrintType("const char[]");
  PrintType("const char[15]");
  PrintType("const char[5]");
}

output when run in Windows 7 - VS 2008

const char* type const char*
const char[] type Generic
const char[15] type const char[15]
const char[5] type Generic
like image 567
Michael Avatar asked Nov 01 '11 00:11

Michael


2 Answers

A specialization for any array of chars is:

template< std::size_t N >
struct Test< const char[N] > { ... };

However you can no longer return a char* from type(), unless you write more metafunctions to turn a non-type template parameter into its textual representation.

like image 168
K-ballo Avatar answered Nov 14 '22 02:11

K-ballo


Try this:

#include <cstdio>
#include <string>

template<class T>
void f2(const T& s) // Handle all kinds of string objects
{ std::printf("string object: %s\n", s.c_str()); }

void f2(const char* s) // Handle const char*
{ std::printf("const char*: %s\n", s); }

// ----------------------------------------------------------------------------

template<size_t N>
void f(const char(&s)[N]) // Handle const char array
{ std::printf("const char[%zu]: %s\n", N, s); }

template<size_t N>
void f(char(&s)[N]) // Handle char array
{ std::printf("char[%zu]: %s\n", N, s); }

template<class T>
inline void f(T&& s) // Handle other cases
{ f2(std::forward<T>(s)); }

int main() {
  std::string stringObj     = "some kind of string object ...";
  char charArr[]            = "char array";
  const char constCharArr[] = "const char array";
  const char* constCharPtr  = "const char pointer";

  f(stringObj);
  f(charArr);
  f(constCharArr);
  f(constCharPtr);
  //f("const char array");
}

Output:

string object: some kind of string object ...
char[11]: char array
const char[17]: const char array
const char*: const char pointer

Explanation

f() has two kinds of overloads: One for char arrays and one for "everything else".

f2() handles the "everything else" case.

like image 1
braph Avatar answered Nov 14 '22 03:11

braph