PierreBdR
PierreBdR

Reputation: 43264

Handling of references in C++ templates

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 ...

Upvotes: 2

Views: 247

Answers (4)

Dean Michael
Dean Michael

Reputation: 3496

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_ {};

Upvotes: 1

Leandro T. C. Melo
Leandro T. C. Melo

Reputation: 4032

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)
{
  /* ... */
}

Upvotes: 1

Partial
Partial

Reputation: 9989

Using traits or template specialization would make it work.

Upvotes: 0

James
James

Reputation: 25533

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.

Upvotes: 4

Related Questions