Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Help with operator overloading definition and (possibly) link problems

40 views
Skip to first unread message

Noob

unread,
Sep 11, 2014, 3:30:41 PM9/11/14
to
Hi there.

I'm performing my first experiments in C++ and I'm having a
bit of trouble when trying put the definition of an operator
overloading in a separate file.

I understand the example is a bit silly but anyways.

The following code when written in a single file will work
and output the desired results:

$cat foo_main.cpp

#include <iostream>
#include <array>

template<typename T, std::size_t SIZE>
std::array<T,SIZE> operator+(const std::array<T,SIZE>& a,
const std::array<T,SIZE>& b)
{

std::array<T,SIZE> result;

for(unsigned int i = 0; i < a.size(); ++i)
{
result[i] = a[i] + b[i];
}

return result;
}


int main()
{

std::array<double, 10> arr1, arr2, arr3;

for(unsigned int i = 0; i < arr1.size(); i++)
{
arr1[i] = i;
arr2[i] = 2*i;

}

arr3 = arr1 + arr2;

for(unsigned int i = 0; i < arr3.size(); ++i)
{
std::cout << arr3[i] << std::endl;
}


}

$ g++ --version
g++ (Debian 4.7.2-5) 4.7.2

$g++ -std=c++11 foo_main.cpp && ./a.out
0
3
6
9
12
15
18
21
24
27


Now let

$cat foo.h
#ifndef FOO_H_INCLUDED
#define FOO_H_INCLUDED

#include <array>

template<typename T, std::size_t SIZE>
std::array<T,SIZE> operator+(const std::array<T,SIZE>& a,
const std::array<T,SIZE>& b);


$ cat foo.cpp
#include <array>
#include "foo.h"

template<typename T, std::size_t SIZE>
std::array<T,SIZE> operator+(const std::array<T,SIZE>& a,
const std::array<T,SIZE>& b)
{

std::array<T,SIZE> result;

for(unsigned int i = 0; i < a.size(); ++i)
{
result[i] = a[i] + b[i];
}

return
result;
}

$ cat main_split.cpp
#include "foo.h"
#include <iostream>
#include <array>

int main()
{

std::array<double, 10> arr1, arr2, arr3;

for(unsigned int i = 0; i < arr1.size(); i++)
{
arr1[i] = i;
arr2[i] = 2*i;

}

arr3 = arr1 + arr2;

for(unsigned int i = 0; i < arr3.size(); ++i)
{
std::cout << arr3[i] << std::endl;
}


}

$g++ -std=c++11 main_split.cpp foo.cpp

/tmp/cczMGm79.o: In function `main':
main_split.cpp:(.text+0xdc): undefined reference to
`std::array<double, 10ul> operator+<double, 10ul>(std::array<double,
10ul> const&, std::array<double, 10ul> const&)'
collect2: error: ld returned 1 exit status


I don't know what is the problem. I can compile a similar
program declaring simple functions in separate files but not
this particular case.

Thanks in advance for any help.













Paavo Helde

unread,
Sep 11, 2014, 4:12:50 PM9/11/14
to
Noob <no...@nono.com> wrote in news:lust8k$8oq$1...@dont-email.me:

> Hi there.
>
> I'm performing my first experiments in C++ and I'm having a
> bit of trouble when trying put the definition of an operator
> overloading in a separate file.

See http://www.parashift.com/c++-faq/templates-defn-vs-decl.html

Actually, once there, better read through the whole FAQ.

Cheers
Paavo

Noob

unread,
Sep 11, 2014, 5:03:51 PM9/11/14
to
Thank you very much. There's -a lot- of useful information there.

In my case, would you recommend me to move the definition of the
template to the header file or to do the second solution shown here:

http://www.parashift.com/c++-faq/separate-template-fn-defn-from-decl.html

The former seems easy enough but I wouldn't like to make a habit
of it if it happens to be a source of future complications.

The latter solution implies in telling the compiler which
instantiations I'll actually need (right?) but I'm not sure
how to deal with it in my case without explicitly declaring a
SIZE.

Thanks again.

Paavo Helde

unread,
Sep 12, 2014, 2:17:34 AM9/12/14
to
Noob <no...@nono.com> wrote in news:lut2m8$ihb$1...@dont-email.me:

> Thank you very much. There's -a lot- of useful information there.
>
> In my case, would you recommend me to move the definition of the
> template to the header file or to do the second solution shown here:
>
> http://www.parashift.com/c++-faq/separate-template-fn-defn-from-
decl.html
>
> The former seems easy enough but I wouldn't like to make a habit
> of it if it happens to be a source of future complications.

[for the record: the second solution means explicit instantiation of
templates in a single source file]

In software development (and probably especially with C++) you will
notice in time that complexity tends to increase "by itself" and fighting
with the complexity is the most important thing to do. So the rule of
thumb is to always prefer the simplest solution if possible, and here the
first solution (putting all templates in header files) is definitely the
simplest one and means least headaches to write and maintain. Many
template libraries are actually header-only (including many parts of
STL), so the compilers are ready to cope with them.

Many people see that the first solution actually has several advantages:
no need to guess which instantiations are required by the program, plus
better optimization possibilities for the compiler (as the function
definitions are visible inline). The only downside is that the compiling
times might become larger, to fight this one can just keep the header
files concsice and include them only in source files which actually need
them.

I would suggest to use the second solution (explicit instantiation in a
source file) only when you are experienced enough to decide this is a
better solution.

Cheers
Paavo

Wouter van Ooijen

unread,
Sep 12, 2014, 4:05:25 AM9/12/14
to
Paavo Helde schreef op 12-Sep-14 8:17 AM:
That advice totally matches the third law of optimization: optimize only
when you know there is a (speed or other) problem. (The first two law's
are of course "don't" and "don't").

Wouter

Juha Nieminen

unread,
Sep 12, 2014, 7:16:09 AM9/12/14
to
Noob <no...@nono.com> wrote:
> $ cat foo.cpp
> #include <array>
> #include "foo.h"
>
> template<typename T, std::size_t SIZE>
> std::array<T,SIZE> operator+(const std::array<T,SIZE>& a,
> const std::array<T,SIZE>& b)
> {
>
> std::array<T,SIZE> result;
>
> for(unsigned int i = 0; i < a.size(); ++i)
> {
> result[i] = a[i] + b[i];
> }
>
> return
> result;
> }

You need to instantiate it in *this* compilation unit with every
type it's being used with anywhere else.

Unfortunately since C++ does not support export templates (anymore),
the compiler won't do it for you. You'll have to do it manually.

If you want to do it like that, you need explicit instantiation
(google for "template explicit insantiation").

However, the easiest way is to simply do it like you did in your
first example, and put the implementation in the same header file
where the declaration is.

--- news://freenews.netfront.net/ - complaints: ne...@netfront.net ---

Jorgen Grahn

unread,
Sep 13, 2014, 2:27:37 AM9/13/14
to
On Thu, 2014-09-11, Noob wrote:
> Hi there.
>
> I'm performing my first experiments in C++ and I'm having a
> bit of trouble when trying put the definition of an operator
> overloading in a separate file.
>
> I understand the example is a bit silly but anyways.
>
> The following code when written in a single file will work
> and output the desired results:
>
> $cat foo_main.cpp
>
> #include <iostream>
> #include <array>
>
> template<typename T, std::size_t SIZE>
> std::array<T,SIZE> operator+(const std::array<T,SIZE>& a,
> const std::array<T,SIZE>& b)
> {
>
> std::array<T,SIZE> result;
>
> for(unsigned int i = 0; i < a.size(); ++i)
> {
> result[i] = a[i] + b[i];
> }
>
> return result;
> }

A different critique: here you're saying array + array means, in your
whole program and for any arrays, element-wise addition.

I'm all for operator overloading, but this one is a bit hard to
swallow. For one thing, it will only work when T + T is defined.

(And it won't work as-is for int + long and so on.)

Also, if you're new to C++ perhaps you should stick to std::vector at
first, unless you have very special needs. If you're coming from C,
std::vector is the one that should replace most C-style arrays.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Noob

unread,
Sep 15, 2014, 3:41:11 PM9/15/14
to
Thank you. Your reply was much appreciated!

Noob

unread,
Sep 15, 2014, 3:51:26 PM9/15/14
to
Thank you Jorgen.

I'll be using this in a very specialized application. Since I'll always
be using arrays of doubles, I thought that it should represent no real
problem. I was also reading about type_traits. Maybe I should use it.
Also, this overload definition will be put in a specific namespace.

Thanks again.




0 new messages