pass-by-reference for template?

J

Jess

Hello,

I learned that when I work with templates in C++, I should have
functions that pass arguments by reference because the type of object
is not known. Does it mean that if I have a function that is template
function, then it's argument should be a reference type, such as the
following?

template<class T>
void f(T& t){...}

What if I replace the signature by

template<class T>
void f(T t){...}

or

template<class T>
void f(T* tp){...}

Would it work and if not, could someone tell me why please?

Thanks,
Jess
 
J

Jim Langston

Jess said:
Hello,

I learned that when I work with templates in C++, I should have
functions that pass arguments by reference because the type of object
is not known. Does it mean that if I have a function that is template
function, then it's argument should be a reference type, such as the
following?

template<class T>
void f(T& t){...}

What if I replace the signature by

template<class T>
void f(T t){...}

or

template<class T>
void f(T* tp){...}

Would it work and if not, could someone tell me why please?

It would work the same way a function would work. So, yes, it would work
the because
void f(int* tp) {/*...*/}
would work.
 
?

=?ISO-8859-1?Q?Erik_Wikstr=F6m?=

Hello,

I learned that when I work with templates in C++, I should have
functions that pass arguments by reference because the type of object
is not known. Does it mean that if I have a function that is template
function, then it's argument should be a reference type, such as the
following?

I don't see much connection between templates and using references. In
general, using references is often better than passing by value, whether
you are using templates or not, since it requires less copying.
template<class T>
void f(T& t){...}

What if I replace the signature by

template<class T>
void f(T t){...}

The reference version is slightly better since it does not require the
type used to be copyable. While most types are copyable there are
instances where it might be beneficial to disallow copying.
template<class T>
void f(T* tp){...}

When using pointers you always run the risk of someday getting a NULL-
pointer, with references you don't.
 
A

Alf P. Steinbach

* Erik Wikström:
I don't see much connection between templates and using references. In
general, using references is often better than passing by value, whether
you are using templates or not, since it requires less copying.


The reference version is slightly better since it does not require the
type used to be copyable. While most types are copyable there are
instances where it might be beneficial to disallow copying.

Well. If T is non-const, then

T&

requires an lvalue actual argument (because an rvalue can't be bound to
a reference).

And if T is const, that is, T is mapped to U const, then with the
current standard

U const&

requires U to have an accessible copy constructor.

Still, in practice it's a good idea to write

void foo( T const& v )

instead of the Java-like

void foo( T v )

because where this choice matters, the reference to const will be
preferable (it's especially an issue for std::string).

Going down to the premature optimization level the choice can be
automated, e.g. as described in Alexandrescu's "Modern C++ Design". But
that complicates the code -- reduces clarity -- for little or no
real gain. However, for completeness, using Boost you can do

void foo( boost::call_traits<T>::param_type v )

and have the selection of T const& or just plain T, automated, depending
on what's most micro-efficient.

Cheers, and hth.,

- Alf
 
A

Alf P. Steinbach

* Alf P. Steinbach:
* Erik Wikström:

Well. If T is non-const, then

T&

requires an lvalue actual argument (because an rvalue can't be bound to
a reference).

And if T is const, that is, T is mapped to U const, then with the
current standard

U const&

requires U to have an accessible copy constructor.

"an rvalue U".
 
A

Alf P. Steinbach

* Alf P. Steinbach:
* Erik Wikström:

Well. If T is non-const, then

T&

requires an lvalue actual argument (because an rvalue can't be bound to
a reference).

And if T is const, that is, T is mapped to U const, then with the
current standard

U const&

requires U to have an accessible copy constructor.

"an rvalue U".
 
J

Jess

Thanks for your replies. The reason I asked the question is that I
was told to use reference rather the actual value because T is a
template parameter and it's value isn't known until instantiation. Is
this not so? or, is there some other kind of template functions that
require the use of reference rather than the actual type?

Thanks,
Jess
 
J

Jess

* Erik Wikström:






Well. If T is non-const, then

T&

requires an lvalue actual argument (because an rvalue can't be bound to
a reference).

And if T is const, that is, T is mapped to U const, then with the
current standard

U const&

requires U to have an accessible copy constructor.

Do you mean I can use const T& but not T& here? If I have a non-
template function, I can always have both a const-ref version and a
non-const-ref version. Is this not true for template functions?

Thanks,
Jess
 
?

=?ISO-8859-1?Q?Erik_Wikstr=F6m?=

Thanks for your replies. The reason I asked the question is that I
was told to use reference rather the actual value because T is a
template parameter and it's value isn't known until instantiation. Is
this not so? or, is there some other kind of template functions that
require the use of reference rather than the actual type?

In the future please quote the text you are replying to.

It's kind of true but irrelevant, templates are instantiated during
compilation so the compiler knows the type when it needs to. In other
words you won't risk getting your classes sliced or such, like you would
with runtime polymorphism.

The fact that a template is involved have nothing do do with the usage
of references, however using references (or const references) is
generally a good idea (even if you don't work with templates) since it
prevents unnecessary copying.
 
?

=?ISO-8859-1?Q?Erik_Wikstr=F6m?=

Do you mean I can use const T& but not T& here? If I have a non-
template function, I can always have both a const-ref version and a
non-const-ref version. Is this not true for template functions?

You can have both const and non-const with templates, the issue has
nothing to do with templates per se, it's just that const ref is the
most flexible way to pass arguments. Consider the following code:

class Foo
{
Foo(const Foo&);
Foo& operator=(const Foo&);
int v;
public:
Foo(int i) : v(i) {}
};

void val(Foo);

void ref(Foo&);

void cref(const Foo&);

int main()
{
Foo f(1);


// [1]
val(f);
ref(f);
cref(f);

// [2]
ref(Foo(1));
cref(Foo(1));
}

The class Foo can not be copied (the copy ctor is private), the three
function each use different ways to pass parameters. If you try to
compile the code you'll notice that the call to val(f) under [1] does
not work. This is because passing by value requires that you can copy
the object passed. IF you comment out that call you'll see that both
ref(f) and cref(f) works.

Next we'll look at the difference between ref and const ref, to do this
comment out the copy ctor in Foo (this will allow the compiler to
generate one). You'll now notice that ref(Foo(1)) does not compiler but
that cref(Foo(1)) does, this is because a const ref can bind to an
r-value while a normal ref can't.

As you can see a const ref is more versatile than a ref, which is more
versatile than passing by value, plus that you don't get the overhead of
copying the object. So if you can using a const ref is usually a good
idea since it will allow usages that ways wont.
 
J

Jess

Do you mean I can use const T& but not T& here? If I have a non-
template function, I can always have both a const-ref version and a
non-const-ref version. Is this not true for template functions?

You can have both const and non-const with templates, the issue has
nothing to do with templates per se, it's just that const ref is the
most flexible way to pass arguments. Consider the following code:

class Foo
{
Foo(const Foo&);
Foo& operator=(const Foo&);
int v;
public:
Foo(int i) : v(i) {}

};

void val(Foo);

void ref(Foo&);

void cref(const Foo&);

int main()
{
Foo f(1);

// [1]
val(f);
ref(f);
cref(f);

// [2]
ref(Foo(1));
cref(Foo(1));

}

The class Foo can not be copied (the copy ctor is private), the three
function each use different ways to pass parameters. If you try to
compile the code you'll notice that the call to val(f) under [1] does
not work. This is because passing by value requires that you can copy
the object passed. IF you comment out that call you'll see that both
ref(f) and cref(f) works.

Next we'll look at the difference between ref and const ref, to do this
comment out the copy ctor in Foo (this will allow the compiler to
generate one). You'll now notice that ref(Foo(1)) does not compiler but
that cref(Foo(1)) does, this is because a const ref can bind to an
r-value while a normal ref can't.

As you can see a const ref is more versatile than a ref, which is more
versatile than passing by value, plus that you don't get the overhead of
copying the object. So if you can using a const ref is usually a good
idea since it will allow usages that ways wont.

Thanks for the examples and explanations! :)
Jess
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top