Reputation: 798
I have read many questions like this and I am not 100% sure if mine's any different. I have searched quite a lot for the right answer but most of the answers were around macro gaurds. I had a custom string class that I derived from std::string
, and later on since I was using that project in real world so I did not want to derive std::string just for the sake of extending functionality. So I moved the functions from customString.h into utils_string.h. Here is the definition:
#ifndef OPS_TOOLKIT_UTILS_STRING_H
#define OPS_TOOLKIT_UTILS_STRING_H
#include <string>
#include <algorithm>
#include <vector>
namespace utils{
namespace string{
const std::string kilikeDelimiter = "%";
void tolower(std::string& str){
//CODE
}
bool iequals(const std::string& str1,const std::string& str2){
//CODE
}
bool ilike(const std::string& str,const std::string& pattern){
//CODE
}
std::string prependAndAppendILikeDelimiter(const std::string& str) {
//CODE
}
} //namespace string
} //namespace utils
#endif
and I get complains about ...first defined here
and here is exact output from compiler. Note: no class here
/tmp/ccCFVTXP.o: In function
utils::string::tolower(std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)': listings.cpp:(.text+0x0): multiple definition of
utils::string::tolower(std::basic_string, std::allocator >&)' /tmp/cczDtRdT.o:listing.cpp:(.text+0x0): first defined here /tmp/ccCFVTXP.o: In functionutils::string::iequals(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)': listings.cpp:(.text+0x55): multiple definition of
utils::string::iequals(std::basic_string, std::allocator > const&, std::basic_string, std::allocator > const&)' /tmp/cczDtRdT.o:listing.cpp:(.text+0x55): first defined here /tmp/ccCFVTXP.o: In functionutils::string::ilike(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)': listings.cpp:(.text+0x118): multiple definition of
utils::string::ilike(std::basic_string, std::allocator > const&, std::basic_string, std::allocator > const&)' /tmp/cczDtRdT.o:listing.cpp:(.text+0x118): first defined here /tmp/ccCFVTXP.o: In functionutils::string::prependAndAppendILikeDelimiter(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)': listings.cpp:(.text+0x484): multiple definition of
utils::string::prependAndAppendILikeDelimiter(std::basic_string, std::allocator > const&)' /tmp/cczDtRdT.o:listing.cpp:(.text+0x484): first defined here /tmp/ccifZISK.o: In functionutils::string::tolower(std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)': match_count.cpp:(.text+0x0): multiple definition of
utils::string::tolower(std::basic_string, std::allocator >&)' /tmp/cczDtRdT.o:listing.cpp:(.text+0x0): first defined here /tmp/ccifZISK.o: In functionutils::string::iequals(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)': match_count.cpp:(.text+0x55): multiple definition of
utils::string::iequals(std::basic_string, std::allocator > const&, std::basic_string, std::allocator > const&)' /tmp/cczDtRdT.o:listing.cpp:(.text+0x55): first defined here /tmp/ccifZISK.o: In functionutils::string::ilike(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)': match_count.cpp:(.text+0x118): multiple definition of
utils::string::ilike(std::basic_string, std::allocator > const&, std::basic_string, std::allocator > const&)' /tmp/cczDtRdT.o:listing.cpp:(.text+0x118): first defined here /tmp/ccifZISK.o: In functionutils::string::prependAndAppendILikeDelimiter(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)': match_count.cpp:(.text+0x484): multiple definition of
utils::string::prependAndAppendILikeDelimiter(std::basic_string, std::allocator > const&)' /tmp/cczDtRdT.o:listing.cpp:(.text+0x484): first defined here collect2: ld returned 1 exit status
I am sorry for whole mess but I didn't want to miss anything for anyone who has come across similar problem.
One more thing; where it says match_count.cpp *listing.cpp* and listings.cpp it's just using the functions defined in ::utils::string::function()
Upvotes: 1
Views: 2126
Reputation: 300
It may be better to put your functions into a class like this (the following goes to a .h file). It's probably more common that using nested namespace.
#pragma once
#include <string>
namespace utils
{
class StringUtil
{
public:
static void tolower(std::string& str)
{
// code
}
};
}
Upvotes: 0
Reputation: 5431
A header file cannot define code unless it is explicitly inline
. Otherwise (because the preprocessor works like a giant copy/paste machine) it is as if the functions are defined once for every file that does a #include
.
So add inline
to each of those, or put them in a single .cpp
, but not in a header.
Upvotes: 4