views:

156

answers:

4

I currently have a function template, taking a reference, that does something in essence equivalent to:

template <typename T>
void f(T& t)
{
   t = T();
}

Now, I can call:

int a;
f(a);

To initialize my variable a. I can even do:

std::vector<int> a(10);
f(a[5]);

However, this will fail:

std::vector<bool> a(10);
f(a[5]);

The reason being a[5] returns an object with reference semantic, but not a reference. So I need to be able to write:

template <typename T>
void f(T a)
{
  a = T();
}

But if I add this new template and try to compile the first example (with int), I obtain the following error:

test_multi_tmpl.cc: In function ‘int main()’:
test_multi_tmpl.cc:20: error: call of overloaded ‘f(int&)’ is ambiguous
test_multi_tmpl.cc:6: note: candidates are: void f(T&) [with T = int]
test_multi_tmpl.cc:12: note:                 void f(T) [with T = int]

Any ideas how to solve this? I wouldn't like to overload f just for std::vector<bool>::reference as this construct might appears in other places ...

+4  A: 

I think specialising f for std::vector<bool>::reference is your only option.

Note that using std::vector<bool> is probably a bad idea in the first place (the std::vector<bool> specialisation is deprecated for future versions of the c++ language) so you could just use std::deque<bool> instead.

Autopulated
`vector<int>` might work too.
Fred Larson
`vector<char>` would technically be closer.
Pavel Minaev
The specialization `std::vector<bool>` is indeed deprecated, but why stop using a vector of booleans ?
Matthieu M.
The specialization is deprecated, but it remains; therefore, whenever you write `vector<bool>`, you _will_ get that specialization (any implementation that doesn't do so is non-conformant), with all its problems.
Pavel Minaev
I might have more clearly said that using vector<bool> is a bad idea because the specialisation isn't gone *yet*
Autopulated
@Pavel: I am not sure about it, they are probably just as bad from a standard point of view. AFAIK, or IIRC the standard does not define what the size of a bool variable is, so for some architecture/compiler it could well take 16, 32 or even 64 bits. Depending on the architecture and your constraints you might want to use `vector<int>` for performance reasons if the size is small.
David Rodríguez - dribeas
A: 

Using traits or template specialization would make it work.

Partial
I presume he wants it to work for any "reference-like type", not just specifically for `vector<bool>::reference`. And what traits would you use here?
Pavel Minaev
+1  A: 

There are two ways to do this, one is, as you suggest, specialize for std::vector<bool>::reference. The other is by using type-traits dispatching.

template <class T>
void f (T& t) {
  f_impl(t, is_reference_wrapper_type<T>());
}

template <class T>
void f_impl(T& t, mpi::false_) {
  t = T();
}

template <class T>
void f_impl(T& t, mpi::true_) {
  // do nothing, or voodoo here
}

Note the code above is un-tested and there would be more complex means of dispatching based on a trait -- or a set of traits -- in this situation.

This would also mean that you would need to implement is_reference_wrapper_type like so:

template <class T>
struct is_reference_wrapper_type : mpi::false_ {};

template <>
struct is_reference_wrapper_type<std::vector<bool>::reference> : mpi::true_ {};
Dean Michael
That wouldn't work, as with your code, if I call `int a; f(a);`, that will never use a as a reference.
PierreBdR
Oh you're right. Let me edit to fix it.
Dean Michael
mmmhh ... actually, that doesn't solve the problem ! That still doesn't allow for this: vector<bool> a(10); f(a[5]);
PierreBdR
Of course you need to handle the case when the parameter is a `vector<bool>::reference` specially. Your interface to f(...) doesn't change but your specific implementation does. Then of course you need to extend this not only for `vector<bool>::refence` in case you're feeling adventurous to support other reference wrapper types.
Dean Michael
+1  A: 

I'm not sure whether you already know about this...

The specialization std::vector is not really a STL container because it does not meet the necessary requirements. In particular, it's not possible to created proxied containers that satisfy the STL concepts because of the reference semantics (you can't fake a reference). Check this article for more information. (Also, as Autopulated mentioned there should be a compiler directive to provide control over std::vector in the future C++ Standard.)

A simple workaround that could solve your problem is by overloading function f for this particular type (and others if they appear and are not many). Notice that this is an overload and not an specialization. You might also wanna check this for why not specialize function templates.


void f(std::vector<bool>::reference t)
{
  /* ... */
}
ltcmelo
I know I could overload. But as I stated, I would like to *not* do that. For one, that would work only for this specific case, and also, this is not really a function, but a method in my case. So I cannot have all the possible methods already in the class.
PierreBdR