I would be grateful if someone could point out if I am understanding
correctly and suggest ways to improve. Sorry for the long message and
I hope you will kindly bear with it. I have to make it elaborate to
make sure my questions are clear enough.
Let's say I need to write a function whose logic is same for all types
(T) except in the case of T * (including const T *). Furtheremore ,
the function needs to be written differently for character
strings(C-style).
I have tried various combination of explicit specialization and
overloading and came to the following conclusion:
1. I need to have a template for T
2. I need to overload the template for T *
3. I need to have explicit specialization or a normal function for
char *
4. I need to have explicit specialization or a normal function for
const char *
I tried to make 3 & 4 into one (hoping const char * will accept char
*), but I learned it cannot be when 1 or 2 is present since char *
will be instantiated from the template.
My questions are:
A. Since their logic will be exactly same, is there a way to make 3
and 4 into one function?
B. Passing arrays of T will be resolved into case 2. What if I don't
wish to treat arrays of T as pointers to T? Let's say the logic of
working on pointers to T will give unexpected result when worked on
arrays of T. Is there any way to treat arrays of T differently from
pointers to T?
C. The primary template passes by value. Can I make it
pass-by-const-reference?
Actually, I made my attempt at this and needs to know if I am doing
right.
Here is a simple program I wrote to help me understand what's going
on:
#include <iostream>
using std::cout;
template <typename T>
void func(T)
{ cout << "primary\n" ; }
template <typename T>
void func(T *) // should handle T * as well as const T *, I think
{ cout << "Overloading for Pointers\n"; }
template <>
void func(char *)
// BTW, Writing above as func<char *> makes gcc behave differently
{ cout << "specialization: char * \n"; }
template <>
void func(const char *)
// BTW, Writing above as func<const char *> makes gcc behave
differently
{ cout << "specialization: const char * \n"; }
int main()
{
char * pc = "whatever";
const char * pcc = "whatever";
char ac[] = "whatever";
const char acc[] = "whatever";
int i;
const int ci=1;
int ai[] = { 0 };
const int aci[] = {0};
cout << "int: "; func(i);
cout << "int *: "; func(&i);
cout << "const int: "; func(ci);
cout << "const int *: "; func(&ci);
cout << "int [] : "; func(ai);
cout << "const int [] :"; func(aci);
cout << "Literal String: "; func("whatever");
cout << "char *: "; func(pc);
cout << "const char *: "; func(pcc);
cout << "char []: "; func(ac);
cout << "const char[]: "; func(acc);
}
As asked in question C, can I make the primary function template pass
by const-reference to T? Here is my attempt but it looks rather
horrible as I need to provide the four different explicit
specializations whose internal logics are exactly same for handling
C-style strings. And I think this would also create code bloat as
different instantiations will be made for array of char of different
sizes.
Please have a look and give me some advice if I can make those four
separate explicit specialization combined into one (maybe two?)
#include <iostream>
using std::cout;
template <typename T>
void func(const T &)
{ cout << "primary\n" ; }
template <typename T>
void func(T * const &)
{ cout << "Overloading for Pointers\n"; }
template <>
void func(char * const &)
{ cout << "specialization: char * \n"; }
template <>
void func(const char * const &)
{ cout << "specialization: const char * \n"; }
template <int N>
void func( const char (&) [N] )
{ cout << "Overloading for const char[] \n"; }
template <int N>
void func( char (&) [N] )
{ cout << "Overloading for char[] \n"; }
/*
template <typename T, int N>
void func( T (&) [N] )
{ cout << "Overloading for T [] \n"; }
*/
// Including this creates ambiguity for arrays of T
// as it collides with the primary one.
int main()
{
char * pc = "whatever";
const char * pcc = "whatever";
char ac[] = "whatever";
const char acc[] = "whatever";
int i;
const int ci=1;
int ai[] = { 0 };
const int aci[] = {0};
cout << "int: "; func(i);
cout << "int *: "; func(&i);
cout << "const int: "; func(ci);
cout << "const int *: "; func(&ci);
cout << "int [] : "; func(ai);
cout << "const int [] :"; func(aci);
cout << "Literal String: "; func("whatever");
cout << "char *: "; func(pc);
cout << "const char *: "; func(pcc);
cout << "char []: "; func(ac);
cout << "const char []: "; func(acc);
}
Question B.2: Now, arrays of T are resolved into primary template. Is
there any way to differentiate between T and array of T?
Thank you for your patience, time and kind advice in advance.