问题
I've looked over a few similar questions, but I'm still confused. I'm trying to figure out how to explicitly (not by compiler optimization etc) and C++03-compatible avoid copying of an object when passing it to a specialized template function. Here is my test code:
#include <iostream>
using namespace std;
struct C
{
C() { cout << "C()" << endl; }
C(const C&) { cout << "C(C)" << endl; }
~C() { cout << "~C()" << endl; }
};
template<class T> void f(T) { cout << "f<T>" << endl; }
// This shows two possible ways, I don't need two overloads
// If I do it like (2) the function is not called, only if I do it like (1)
template<> void f(C c) { cout << "f<C>" << endl; } // (1)
template<> void f(const C& c) { cout << "f<C&>" << endl; } // (2)
int main()
{
C c;
f(c);
return 0;
}
(1) accepts the object of type C
, and makes a copy. Here is the output:
C()
C(C)
f<C>
~C()
~C()
So I've tried to specialize with a const C&
parameter (2) to avoid this, but this simply doesn't work (apparently the reason is explained in this question).
Well, I could "pass by pointer", but that's kind of ugly. So is there some trick that would allow to do that somehow nicely?
EDIT: Oh, probably I wasn't clear. I already have a templated function
template<class T> void f(T) {...}
But now I want to specialize this function to accept a const& to another object:
template<> void f(const SpecificObject&) {...}
But it only gets called if I define it as
template<> void f(SpecificObject) {...}
Basically what I want to do with this specialization is to adapt the SpecificObject
to the template interface like
template<> void f(SpecificObject obj){ f(obj.Adapted()); } // call the templated version
EDIT2: Ok, I can force the const C&
specialization to be called this way:
f<const C&>(c);
but is there a way to make it work like this as just f(c)
?
EDIT3: If someone would eventually have similar questions, I finally found this link in another question, and it is helpful: http://www.gotw.ca/publications/mill17.htm
回答1:
So if you don't always want to accept a const reference (which is reasonable for base types [int, long, float etc.]), you can use a little boost magic.
#include <iostream>
#include <boost/call_traits.hpp>
using namespace std;
struct C
{
C() { cout << "C()" << endl; }
C(const C&) { cout << "C(C)" << endl; }
//C& operator=(C const&) { cout << "C=C" << endl; return *this; }
~C() { cout << "~C()" << endl; }
};
template<class T> void foo(typename boost::call_traits<T>::param_type inst) { cout << "f<T>" << endl; }
// specialization for calling class C
template<> void foo<C>(boost::call_traits<C>::param_type inst) { cout << "f<C>" << endl; }
int main()
{
int i = 0;
foo<int>(i);
C c;
foo<C>(c);
return 0;
}
回答2:
You're conflating three issues: templates, overloading and argument passing.
Just remove the specializations and pass the argument as T const&
.
Cheers & hth.,
回答3:
Why don't you overload:
void f(const C& c) { cout << "f(const C&)" << endl; }
回答4:
This would work:
int main()
{
C c;
f<const C&>(c);
return 0;
}
Your alternative:
template<typename T> void f(const boost::reference_wrapper<T const>& c)
{ cout << "f<boost_const_ref&>" << endl; }
int main()
{
C c;
f(boost::cref(c));
return 0;
}
In reality you would use boost::reference_wrapper to pass the reference through to where you want to use it. You can use get() to do that, although boost::reference_wrapper has an implicit conversion back to the reference, so you could probably get by without the partial-specialisation of the template and just passing boost::cref(c)
to the regular one.
回答5:
Your problem is that the actual parameter c isn't const, so the main template is a better match because it doesn't need to add 'const' to the type. If you try functions that pass by value and by non-const reference, the compiler will tell you that it cannot resolve that difference.
回答6:
#include <iostream>
using namespace std;
struct C
{
C() { cout << "C()" << endl; }
C(const C&) { cout << "C(C)" << endl; }
~C() { cout << "~C()" << endl; }
};
template<class T> void f(const T&) { cout << "f<T>" << endl; }
int main()
{
C c;
f(c);
return 0;
}
This does do what you would like, but you must then use a const ref for all values passed into the function. I do not know if this was what you were looking for.
来源:https://stackoverflow.com/questions/4875989/template-pass-by-const-reference