I have a question about templates that can be used with parameters that are either a class or a primitive type. Here's some sample code:
(Note: I have real code that's more complex, the following code is useless but it reproduces the same issue)
template<typename T>
class Foo
{
T value;
public:
Foo() {}
const T& getValue() const { return value; }
Foo& setValue(const T& other) {
value = other; return *this;
}
};
struct Bar
{
int x;
Bar() : x(3) {}
};
int doit()
{
Foo<int> fooint;
Bar bar;
bar.x = 44;
Foo<Bar> foobar;
fooint.setValue(3); // warning here
foobar.setValue(bar);
int y = foobar.getValue().x + fooint.getValue();
return y;
}
I get a compiler remark on fooint.setValue()
:
value copied to temporary, reference to temporary used
I understand the remark. What I'm wondering is how I should handle Foo::setValue()
if I'm going to use Foo with both primitives and class/struct types as template parameters.
I thought setValue(const T& other)
was the right method signature for passing in a constant class by reference.
Is there a way to make setValue() so it "does the right thing" both for Foo<int>
and Foo<Bar>
?
It is perfectly legal to bind temporaries to const references as you do in setValue()
. Intel C++, which issues this remark, is not being helpful in this case.
EDIT: I am guessing that TI compiler is based on Intel, which, for me, issues the following diagnostic on that line:
test.cc(28): remark #383: value copied to temporary, reference to temporary used
fooint.setValue(3); // warning here
The diagnostic is discussed on http://software.intel.com/en-us/articles/cdiag383/ where it says
Can safely ignore this warning for pushback function of vector. The vector copies the argument into its own storage; it never stores the original argument. Therefore, using a temporary is perfectly safe.
In your case, you're also copying the argument, therefore it can also be ignored.
I see nothing wrong with your code. GCC compiles it without errors or warnings.
To answer your last question of getting Foo<T>::setValue()
to do the 'right thing' you can consider using template specialization to accomplish that -- a fairly common technique used in template metaprogramming. Something like this for example:
template <typename T>
struct Ref_or_Value
{
typedef T& type;
};
template <typename T>
struct Ref_or_Value<T *>
{
typedef T* type;
};
template <>
struct Ref_or_Value<int>
{
typedef int type;
};
// add other primitive types like above as need
The Foo<T>::setValue
signature then becomes:
Foo& setValue(const typename Ref_or_Value<T>::type other);
Whether this is overkill or not I'll let you decide but this should get setValue to do the 'right thing'. If T=int
then setValue will take arguments by value. If T=Foobar_object
then it will be by const reference.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With