views:

87

answers:

2

I have a "set" data type:

template <class V>
struct Set {
  void add(const V& value) {}
};

I want to write a top-level function version of Set::add.

template <class V>
void add(const Set<V>& set, const V& value) {}

This doesn't quite work with string literals:

Set<const char*> set;
const char* val = "a";

set.add(val); // ok
set.add("a"); // ok

add(set, val); // ok
add(set, "a"); // ERROR
add<const char*>(set, "a"); // ok

The error message (g++ 4.2.4):

no matching function for call to ‘add(Set<const char*>&, const char [2])’

It looks it has something to do with the fact that "a" has type const char[2] and not const char*. Does anybody know how to get this to work?

+4  A: 

The problem is that V gets one type for the left parameter, and another type for the right one. I suspect you also want to be able to say add(setOfLong, 0) - but with that template you couldn't. I recommend to add a separate template parameter to solve this

template <class SetV, class V>
void add(const Set<SetV>& set, const V& value) {}
Johannes Schaub - litb
Ah, I didn't think of this! It's much better than mine.
sbi
Good idea. I do wish that C++'s template argument inference were smart enough to make this unnecessary, but oh well...
Kannan Goundan
A: 

There's another way to solve this problem (forget where I saw it...).

You can use an "Identity" type wrapper to have the compiler not take a type into account when performing inference.

template <T>
struct Identity {
   typedef T type;
};

Then define "add" like this:

template <class V>
void add(const Set<V>& set, const typename Identity<V>::Type& value) {}

This causes 'V' to be deduced solely based on the first argument type. Once that's determined, it goes ahead and uses it for the second argument, which works fine.

Kannan Goundan