0

A related question is in C, but this questions pertains to specifically C++. When I try to compile this code, it gives me the following error message:

In file included from main.cpp:5:
./Any.hpp:20:6: error: function 'any<std::__1::vector<double, std::__1::allocator<double> >, (lambda at main.cpp:12:23)>' is used but not defined in this translation unit, and
      cannot be defined in any other translation unit because its type does not have linkage
bool any(List &elements, Function callback);
     ^
main.cpp:19:9: note: used here
    if (any(doubleElements, doubleFunc)) {
        ^
In file included from main.cpp:5:
./Any.hpp:20:6: error: function 'any<std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > >, (lambda at main.cpp:15:23)>' is used but
      not defined in this translation unit, and cannot be defined in any other translation unit because its type does not have linkage
bool any(List &elements, Function callback);
     ^
main.cpp:22:9: note: used here
    if (any(stringElements, stringFunc)) {
        ^
2 errors generated.

Below are the source files:

Any.h

#ifndef ANY_HPP_INCLUDED
#define ANY_HPP_INCLUDED

/**
 * @author Ben Antonellis
**/

#include <vector>
#include <iostream>

/**
 * Returns True if any of the elements meet the callback functions parameters.
 * 
 * @param elements - A list of elements.
 * @param callback - Callback function to invoke on each element.
 * 
 * @return bool - True if parameters are met, False otherwise.
**/
template <typename List, typename Function>
bool any(List &elements, Function callback);

#endif

Any.cpp

/**
 * @author Ben Antonellis
**/

#include "Any.hpp"

template <typename List, typename Function>
bool any(List &elements, Function callback) {
    for (auto element : elements) {
        if (callback(element)) {
            return true;
        }
    }
    return false;
}

And here's how I'm calling this function:

main.cpp

/**
 * @author Ben Antonellis
**/

#include "Any.hpp"

int main() {

    std::vector<double> doubleElements = {-1.0, -2.0, -3.0};
    std::vector<std::string> stringElements = {"Hello", "Goodbye", "Testing 123"};

    auto doubleFunc = [] (double number) {
        return number < 0;
    };
    auto stringFunc = [] (std::string string) {
        return string.length() > 5;
    };

    if (any(doubleElements, doubleFunc)) {
        std::cout << "Double Success." << std::endl;
    }
    if (any(stringElements, stringFunc)) {
        std::cout << "String Success." << std::endl;
    }

    return 0;
}

This is the current way I am compiling my code:

g++ -std=gnu++2a -c main.cpp Any.cpp

Any help is appreciated, I've been stuck on this for a long time.

1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56
Linny
  • 818
  • 1
  • 9
  • 22
  • 6
    Does this answer your question? [Why can templates only be implemented in the header file?](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) – Richard Critten Mar 24 '20 at 21:41
  • @RichardCritten So I need a `.tpp` file to define the template? – Linny Mar 24 '20 at 21:43
  • @Linny A `.tpp` file works but it doesn't _need_ to be in one. You can put it in the `.hpp` file directly. – Ted Lyngmo Mar 24 '20 at 21:45
  • @TedLyngmo How would I go about doing that in this case? The difference between explicitly instantiating a function instead of defining a function confuses me. – Linny Mar 24 '20 at 21:51
  • 1
    @Linny just replace the 2 lines of code in `Any.h` with all of the code from `Any.cpp` and delete the file `Any.cpp`. Templated functions are instantiated when used and the complete source of the template function needs to be available to the compiler at that point. – Richard Critten Mar 24 '20 at 21:53
  • @RichardCritten Awesome, that's worked. Thank you so much! – Linny Mar 24 '20 at 21:55
  • If you go for explicitly instantiating the function for all the types you aim to support, you _can_ do it in the `.cpp` file, but then I suggest that you change the function declaration in the `.hpp` file to _only_ accept those types too to not let users get linking errors if they try other types. If you don't want to explicitly instantiate it, just move what you put in `Any.cpp` into `Any.hpp` (or `Any.tpp` and make `Any.hpp` include `Any.tpp` at the end). – Ted Lyngmo Mar 24 '20 at 21:56

0 Answers0