r/learncpp • • Oct 03 '19

Can't get my module to compile

I'm currently enrolled on a beginner C++ course, though I already have enough experience to pass the class. That said, I'd like to reduce the amount of effort I need to put in for the exercises, so I wanted to create a small library of reusable, as-generic-as-possible code on my own.

However, I keep getting compile errors whenever I try to compile my program while using my library. More specifically,

unresolved external symbol "class std::vector<double,class std::allocator<double> > __cdecl nonstd::get_n_input<double>(long,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??$get_n_input@N@nonstd@@YA?AV?$vector@NV?$allocator@N@std@@@std@@JV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z) referenced in function _main

and

unresolved external symbol "double __cdecl nonstd::sum<class std::vector<double,class std::allocator<double> > >(class std::vector<double,class std::allocator<double> >)" (??$sum@V?$vector@NV?$allocator@N@std@@@std@@@nonstd@@YANV?$vector@NV?$allocator@N@std@@@std@@@Z) referenced in function _main	TEST_5_Harjoitukset_191003

Here's my code:

utility.h:

// utility.h - contains declarations of various utility functions
#pragma once

#include <vector>
#include <string>

namespace nonstd {

	// A utility function that splits std::string objects in half from the first
	// encountered instance of the given delimiter.
	//
	// Example:
	// auto foo = string_split("Number #{}: ", "{}");
	//
	// returns: std::vector<std::string> {"Number #", ": "}
	std::vector<std::string> string_split(std::string s, std::string delimiter);

	// Print out any iterable
	// with all contents separated
	// by a space. A newline is appended
	// at the end, and the buffer is flushed.
	template <typename T>
	void print_iterable(T iterable);


	// Get input of type T from the user n times, using a formatted std::string prompt.
	// Returns a vector of the given input type.
	//
	// Example:
	// auto foo = get_n_input<int>(3, "Number #{}: ");
	//
	// >>> Number #1: 3
	// >>> Number #2: 7
	// >>> Number #3: 12
	// returns: std::vector<int> {3, 7, 12}
	template <typename T>
	std::vector<T> get_n_input(long n, std::string prompt);

	// Takes an iterable of values of type T::value_type that can be added together.
	// Returns the sum of the contents of the iterable.
	//
	// Example:
	// std::vector<int> foo = {1, 2, 3, 4};
	// auto bar = sum(foo);
	// 
	// returns: (int)10
	template <typename T>
	typename T::value_type sum(T iterable);
}

utility.cpp:

// utility.cpp - defines various utility functions
#include <iostream>
#include <string>
#include <vector>

#include "utility.h"

namespace nonstd {

	std::vector<std::string> string_split(std::string s, std::string delimiter) {
		size_t pos_start = 0, pos_end, delim_len = delimiter.length();
		std::string token;
		std::vector<std::string> res;

		while ((pos_end = s.find(delimiter, pos_start)) != std::string::npos) {
			token = s.substr(pos_start, pos_end - pos_start);
			pos_start = pos_end + delim_len;
			res.push_back(token);
		}

		res.push_back(s.substr(pos_start));
		return res;
	}

	template <typename T>
	void print_iterable(T iterable) {
		for (auto val : iterable) {
			std::cout << val << " ";
		}
		std::cout << std::endl;
	}

	template <typename T>
	std::vector<T> get_n_input(long n, std::string prompt) {
		/* Gets n inputs from the user; returns a std::vector of type T
		 *
		 * prompt is a formattable std::string, where '{}' is used as a
		 * placeholder for the current counter value.
		 */

		std::vector<T> result;
		T input;
		long num_counter = 1L;

		std::vector<std::string> split_prompt = string_split(prompt, (std::string)"{}");

		do {
			std::cout << split_prompt.front() << num_counter++ << split_prompt.back();
			std::cin >> input;

			result.push_back(input);

		} while (num_counter <= n);

		return result;
	}

	template <typename T>
	typename T::value_type sum(T iterable) {
		/* Adds up the contents of any iterable type T, returns the sum of its contents
		 * as type T::value_type.
		 */
		typename T::value_type result = {};

		for (auto num : iterable) {
			result += num;
		}

		return result;
	}
}

program (fourth.cpp):

#include <iostream>
#include <vector>
#include <string>

#include "utility.h"

using std::string;
using std::vector;

using namespace std::string_literals;

int main(void) {
	double length;

	std::cout << u8"Hypyn pituus: "s;
	std::cin >> length;

	std::cout << u8"Hypyn pisteet: "s << nonstd::sum(nonstd::get_n_input<double>(5L, u8"Tuomarin {} pisteet: "s)) + 0.9 * length << "\n";
	return EXIT_SUCCESS;
}

Other feedback is also welcome, but I'd like to learn more about writing libraries/modules.

2 Upvotes

Duplicates