466476 (1) [Avatar] Offline
#1
Hi I got some problems to put the reverse_pairs function which mentioned at the end of chapter 4

here is my header file: lib.h

#include <vector>

template <
typename C,
  typename P1 = typename std::remove_cv<
  typename C::value_type::first_type>::type,
  typename P2 = typename C::value_type::second_type
  >
auto reverse_pairs(const C &items) -> std::vector<std::pair<P2, P1>>;


the related implementation file: lib.cc

#include <algorithm>
#include "lib.h"

template <
  typename C,
  typename P1 = typename std::remove_cv<
    typename C::value_type::first_type>::type,
  typename P2 = typename C::value_type::second_type
  >
auto reverse_pairs(const C &items) -> std::vector<std::pair<P2, P1>> {
  std::vector<std::pair<P2, P1>> result(items.size());

  std::transform(items.cbegin(),
                 items.cend(),
                 result.begin(),
                 [](const std::pair<const P1, P2> &p) {
                   return std::make_pair(p.second, p.first);
                 });

  return result;
}


the main file: main.cc

#include <iostream>
#include <algorithm>
#include "lib.h"

using namespace std;

int main() {
    std::vector<std::pair<int, int>> pairs = { {1, 2}, {2, 3}, {3, 4} };
    auto reversed = reverse_pairs(pairs);
    std::for_each(reversed.cbegin(),
                  reversed.cend(),
                  // oh, this const qualifier seems to be mandantory here
                  [](const std::pair<int, int> &p) -> void {
                    std::cout << p.first << "-" << p.second << " ";
                  });
    std::cout << std::endl;
}


But when I try to compile it using

g++-4.9 -std=c++14 main.cc lib.cc -o main && ./main


It complains that

/tmp/ccQ30s9i.o: In function `main':
main.cc:(.text+0xd2): undefined reference to `std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > reverse_pairs<std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > >, int, int>(std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > const&)'
collect2: error: ld returned 1 exit status


But if I change the template to a trivial type, then the compiler will be happy to compile that for me e.g.:

auto reverse_pairs(std::vector<std::pair<int, int>> items) -> std::vector<std::pair<int, int>> {
  std::vector<std::pair<int, int>> result(items.size());

  std::transform(items.cbegin(),
                 items.cend(),
                 result.begin(),
                 [](const std::pair<const int, int> &p) {
                   return std::make_pair(p.second, p.first);
                 });

  return result;
}


So how can I put that generic reverse_pairs function in a header file and then include it? Thanks in advance!

Ivan Cukic (31) [Avatar] Offline
#2
Hi,

When the template functions (and classes) are concerned, you should put the whole implementation into the header file - not just the declaration*.

Templates in C++ are unique - quite different to what you might have seen in other languages. They are just blueprints for making functions, they are not functions themselves.

A proper function gets created when you try to use it (to instantiate the template), and at that point the whole blueprint should be known.

For example, if you create a template function min<T,T>, but never use it, when you compile the program, not a single line of that function will end up in the compiled binary.

If you call it for min(1, 2), the binary will contain the implementation of min for ints - min<int,int>.

If you call it for min(1, 2) and min(1.0, 2.5), the compiled binary will contain the implementation for min<int, int> and a separate implementation for min<double, double>.


You can also check out the longer explanation at the official C++ FAQ -- https://isocpp.org/wiki/faq/templates#templates-defn-vs-decl

Cheers,
Ivan

* a common alternative to this is to have the declarations in a .h file, and include the .cpp file from it (reversed to the normal situation of including .h from .cpp) - which effectively makes the whole implementation of the template function or a class available by includeing the .h file

p.s. You will probably need to update your compiler for the later examples - gcc 4.9 is quite old (the current stable version is 7.1).