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 ...
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.
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)
{
/* ... */
}
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_ {};
Using traits or template specialization would make it work.
精彩评论