header image
Pointer and Non-Pointer Overloading For Template Functions
February 10th, 2012 under Programming. [ Comments: none ]

Yesterday, I run into the problem that function templates cannot be partially specialized. My goal was to distinguish between pointers and non-pointers.

So trying something like

1
2
3
4
5
6
7
8
9
10
template<typename T>
void foo(T t) { printf("T\n"); }
 
// Variant 1
template<typename T>
void foo<T*>(T t) { printf("T*\n"); }
 
// Variant 2
template<typename T>
void foo<T*>(T* t) { printf("T*\n"); }
template<typename T>
void foo(T t) { printf("T\n"); }

// Variant 1
template<typename T>
void foo<T*>(T t) { printf("T*\n"); }

// Variant 2
template<typename T>
void foo<T*>(T* t) { printf("T*\n"); }

always resulted in a compile error. To resolve this problem we can rely on the good-old function overloading mechanism. So

1
2
3
4
5
template<typename T>
void foo(T t) { printf("T\n"); }
 
template<typename T>
void foo(T* t) { printf("T*\n"); }
template<typename T>
void foo(T t) { printf("T\n"); }

template<typename T>
void foo(T* t) { printf("T*\n"); }

works as expected. However now in the non-pointer case always creates a copy, which isn’t desirable. Thus i experimented with call-by-reference. Everything is straight forward when no const qualifiers are in play but the const-reference case has a pitfall. Let’s have a look at this pitfall.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template<typename T>
void foo(const T& t) { printf("T&\n"); }
 
template<typename T>
void foo(const T*& t) { printf("T*\n"); }
 
int main(void)
{
  int i = 0;
  int* pi = &i;
  const int* cpi = &i;
  foo(i);        // (a) prints T&
  foo(pi);       // (b) prints T&
  foo(cpi);      // (c) prints T*
  return 0;
}
template<typename T>
void foo(const T& t) { printf("T&\n"); }

template<typename T>
void foo(const T*& t) { printf("T*\n"); }

int main(void)
{
  int i = 0;
  int* pi = &i;
  const int* cpi = &i;
  foo(i);        // (a) prints T&
  foo(pi);       // (b) prints T&
  foo(cpi);      // (c) prints T*
  return 0;
}

As indicated, this sample doesn’t produce the expected results. The pitfall lays in the const qualifier. We need to remember that const T* is equal to T const*. New let’s have a look at the type const T*&, which is equal to T const* &. This is a reference to a variable pointer but the pointer points to a constant object. So we could change the address of the pointer from within the function (which isn’t desirable). The call (b) passes a variable of type int* which the compiler tries to match to the two template functions. So the type inference for the first function is T = int* which matches. The second function on the other hand doesn’t match at all because, as we saw earlier, the second function expects a pointer to a const object i.e. const int* or int const*. The call (c) prints T* because it is of this type and is as such a better match for the second function than for the first function. Eventually, we see that what we got is reasonable but not what we wanted.

To determine what we need to write lets look again at the inferred type for call (b) and the first function. We saw that T = int*. To see what we need to write we can simply replace T with the inferred pointer type. Well, hang on that’s what we wrote isn’t it. It’s const T& => const int*& and so we deduce that const T*& should written. Yet, we saw that this isn’t producing what we want. The pitfall is in the place of the const in the first-place. We know that const T& is the same as T const&. If we execute the same substitution as before we get int* const& leading to T* const&. When we test this we get what we want.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template<typename T>
void foo(T const& t) { printf("T&\n"); }
 
template<typename T>
void foo(T* const& t) { printf("T*\n"); }
 
int main(void)
{
  int i = 0;
  int* pi = &i;
  foo(i);        // prints T&
  foo(pi);       // prints T*
  foo(cpi);      // (c) prints T*
  return 0;
}
template<typename T>
void foo(T const& t) { printf("T&\n"); }

template<typename T>
void foo(T* const& t) { printf("T*\n"); }

int main(void)
{
  int i = 0;
  int* pi = &i;
  foo(i);        // prints T&
  foo(pi);       // prints T*
  foo(cpi);      // (c) prints T*
  return 0;
}

The problem was that I forgot the realize that the const in const T& is “bound” to the reference. Well, it’s a stupid mistake when you think about it but it needed some thinking :P It might be a good idea to get used to writing T const& instead of const T&.


C++ Marco Debug Options
January 26th, 2012 under Programming. [ Comments: none ]

To be honest, it should be straight forward but I took me a while to figure it out.

I wanted to mark certain lines in the code such that I can easily enable/disable it. So here it is:

1
2
3
4
5
6
7
8
9
10
11
12
13
// set to 1 to enable timing and output
#if 0
   #define TIMING
   #define OUTPUT
#else
   #define TIMING / ## /
   #define OUTPUT / ## /
#endif
...
   TIMING startTimer();
   ...
   TIMING stopTimer();
...
// set to 1 to enable timing and output
#if 0
   #define TIMING
   #define OUTPUT
#else
   #define TIMING / ## /
   #define OUTPUT / ## /
#endif
...
   TIMING startTimer();
   ...
   TIMING stopTimer();
...

when #define TIMING / ## / is used then TIMING is replaced with //. Thus the entire line is commented and therefore disabled. This way i can easily turn on/off several debugging facilities.

The ## in the macro definition means that the previous and successive pieces of text are concatenated. So TIMING myCode; results in // myCode;. We cannot use #define TIMING // because the // won’t be parsed as the replacement string, it will be parsed as the comment literal.

This is a simple but handy technique.


C++ Map
January 17th, 2012 under Programming. [ Comments: none ]

Amazing work that shows C++ features and evolution of C++



The Spirit of XMas
November 28th, 2011 under This And That. [ Comments: none ]

This just puts me in the calming Christmas mood ;)

Happy advent


Well….
September 12th, 2011 under This And That. [ Comments: none ]

Have a look at the guy in the background… Enough said :D

(c) de.wikipedia.ch


« Previous entries