Using templates [duplicate] - c++

This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 8 years ago.
I have this bit of code from a stackoverflow question:
template <typename K, typename V>
bool exists_in(std::map<K,V> const& haystack, K const& needle)
{
return haystack.find(needle) != haystack.end();
}
Being a new user of templates, I still understand what is going on here. Only, I can't seem to apply it.
I have defined
class Varinfo; // meta information about vars
std::map<std::string,VarInfo*> g_varMap; // a map between var names and meta-info
In my main c++ code I have this statement:
// various other uses of g_varMap that don't cause errors then
if ( exists_in( g_VarMap, "fred" ) )
that generates this error.
undefined reference to `bool exists_in<std::basic_string<char,
std::char_traits<char>, std::allocator<char> >,
VarInfo*>(std::map<std::basic_string<char, std::char_traits<char>,
std::allocator<char> >, VarInfo*, std::less<std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >,
std::allocator<std::pair<std::basic_string<char, std::char_traits<char>,
std::allocator<char> > const, VarInfo*> > > const&, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > const&)'
which I completely do not understand.
Can someone tell me why this is complaining? What bitof template knowledge am I missing? I have tried various casting operations on the variable returned by and sent to exists_in() including a std::string( "fred" ). Nothing helped. Some just generated even more meaningless errors.

Undefined reference means it cannot find the definition in any object file. This is a linker error. You need to define the template method within the header file and not in a separate cpp file.
Your code looks okay, I made a rough approximation, you can see it here: http://codepad.org/UvgeTIoC

If your function were available before the point of call you would have no problem. bear in mind that it is template code, so the full implementation has to be included either directly or indirectly:
#include <map>
#include <iostream>
template <typename K, typename V>
bool exists_in(std::map<K,V> const& haystack, K const& needle)
{
return haystack.find(needle) != haystack.end();
}
int main()
{
std::map<int, int> m{{1,1},{2,2}};
std::cout << std::boolalpha;
std::cout << exists_in(m,2) << "\n";
}
output true.

Related

Why does std::list<string> work but not std::list<int>

I'm using templates while implementing AVL trees on Ubuntu.
The file will not compile when I write template class AVLTree<std::list<int> >;, it tells me:
undefined reference to `AVLTree < std::__cxx11::list < std::__cxx11::basic_string < char, std::char_traits < char>, std::allocator < char> >, std::allocator < std::__cxx11::basic_string < char, std::char_traits < char>, std::allocator < char> > > > >::insert(std::__cxx11::basic_string < char, std::char_traits < char>, std::allocator < char> >)'
And I don't get what it doesn't have the reference to.
But it compiles just fine when I write template class AVLTree<std::list<string> >;
I need to let AVLTree store linked lists that store string values.
Why does one compile and the other doesn't? How to solve my problem?
PS: I've included <list>, <string>, and <iostream>, along with my own header file.
Examining the error message closely shows that linker cannot find the AVLTree::insert(string) method.
Based on the sparse information that you posted, my best hypothesis is that you changed the template parameter in the following line from list<string> to list<int>:
template class AVLTree<std::list<string>>;
This line of code explicitly tells the compiler to instantiate a version of the AVLTree template using list<string> as the template parameter. Thus, when you try to compile the code after the change it gives you the error message that it cannot find the AVLTree::insert(string) function because the compiler is now generating the code for list<int> instead.
Your program contains other code that is referencing AVLTree<list<string>>. At a minimum you will have to update that code to use list<int> as well.
Plus, if you simplify the problem down to something you can post the code for on this site, then you will either find the issue during that process or at least have a change of getting a good answer.

how to view std:unordered_map member in GDB

When trying to access a member of std::unordered_map using [], I get an error:
Attempt to take address of value not located in memory.
There is a nice gdb-stl-views, except it does not support unordered_map.
Is there a similarly nice way to retrieve by key a member of unordered_map?
I think you are capable of viewing the member of std::unordered_map with an additional trivial step:
This is my test code:
#include <iostream>
#include <unordered_map>
std::string make_key(const char *input) { return input; }// The additional function to make sure you could construct the key of your map in gdb from primitive type
int main(int argc, char **argv) {
std::unordered_map<std::string, int> map = {
{"bar", 100}
};
std::cout << map.at("bar");
}
And I am using gdb 11.2 in Archlinux:
g++ -std=gnu++11 -O0 -g unordered_map_test.cpp -o unordered_map_test
gdb unordered_map_test
(gdb) p map
$1 = std::unordered_map with 1 element = {["bar"] = 100}
// Perhaps it's useless to print all key-value pairs in map if you have a large map.
// Then you could print value of specific key
(gdb) p map.at(make_key("bar"))
$2 = (std::unordered_map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> > >::mapped_type &) #0x55555556eed8: 100 // 100 is the value of `bar`
// If you think it's annoying that there is too much type information above, you could just print the value after you know the address of value.
(gdb) p *0x55555556eed8
$3 = 100

undefined reference to public methods/variables of a class

I am new to C++. I have a linker problem between 2 files F1 and F2. In order to be more readable, I rewrote the code and output.
F1.h:
class MYCLASS...
public:....// [constructor] etc
void myMethod(const string& r);
static string s;
F1.cpp:
void myMethod(const string& r)
{
MYCLASS::s=r;
}
[...]
void serialize(...)
{
operation(s,...)
}
F2.cpp:
const string& a;
MYCLASS Obj;
Obj.myMethod(a);
The goal is to use the string a from F2.cpp inside the serialize method from F1.cpp, without adding any argument to the serialize function. For that, I am trying to use the intermediate r variable.
The compilation (compiler based on gcc) gives the errors:
In function `the_function_from_F2.cpp(...)':
F2.cpp:227: undefined reference to `MYCLASS::myMethod(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
: In function `myMethod(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
F1.cpp:197: undefined reference to `MYCLASS::s'
: In function `MYCLASS::serialize(....) const':
F2.cpp:69: undefined reference to `MYCLASS::s'
Thank you for any suggestion !
Change to:
void MYCLASS::myMethod(const string& r)
{
MYCLASS::s=r;
}
std::string MYCLASS::s;
This is still a class method, so you need to specify that.
You forgot to actually define the MYCLASS::s member. It has to be done in a source file like
std::string MYCLASS::s;
What you are doing in the class is only declaring the static variable.

C++: What error in using STL vector

I was using the topcoder C++ compiler, and although this code just run fine in Linux gcc, the topcoder compiler gave this error:
your code did not compile:
errors compiling:
Your class or method was improperly declared: In function
‘std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >,
std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > _wrapper::thunk(std::string)’:
Your class or method was improperly declared:20034:
error: conversion from ‘void’ to non-scalar type
‘std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >,
std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >’ requested
This is the code snippet where it is flagging error:
class BinaryCode {
public:
static int get_digit(char c)
{
return (c-'0');
}
void decode(string decd)
{
int i;
std::vector <int> decoded(decd.size());
std::transform(decd.begin(), decd.end(), decoded.begin(), &get_digit);
int length=decoded.size();
This is the topcoder problem description:
Definition Class:BinaryCode
Method:decode
Parameters:string
Returns:vector <string>
Method signature:
vector <string> decode(string message)
(be sure your method is public)
    
Your method signature is:
void decode(string decd)
Should be:
vector <string> decode(string message)
TopCoder compiles your code with testing code for the problem. Make sure the code you provide meets the requirements in the problem statement.
Topcoder compiler is expecting the function to be
vector <string> decode(string message)
while your function is
void decode(string message)
You are using 'void' instead of vector < string >
Try to use
using namespace std;
it fixed my problem. And also includes, it puts your code into separate file
#include <vector>
#include <string>

list<string> cannot pass it to an class in c++

i have an list with some datas list<string> l; and if i pass the value to an class process it gives me error
Process p; p.getnames(l);
and i have an header file process.h with
class Process {
public:
void getnames(list<string> ll);
};
and i have an cpp file process.cpp
void getnames(list<string> ll)
{
// i can use the names here
}
error
undefined reference to `Process::getname(std::list<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >)'
The error you're getting is a linker error because you've defined a free function named getname rather than a member function getname. To fix this, change your .cpp file to have
Process::getname(list<string> names)
And you should be good. The error now is that the compiler thinks you're defining some random function with no connection to Process, so when it compiles the code and someone tries to use Process::getname the linker can't find an implementation for it, and it's not smart enough to know that the free function you defined was intended to be a member function, hence the poor diagnostic.
void Process::getnames(list<string> ll)
{
// i can use the names here
}
When separating definition from declaration, in definition you need to include class name as following:
void Process::getnames(list<string> ll)
{
// i can use the names here
}
What you did is that you defined getnames(list ll) function that returns void.