Majid Q.
Majid Q.

Reputation: 798

First Defined here in g++ from class to namespace

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 ofutils::string::tolower(std::basic_string, std::allocator >&)' /tmp/cczDtRdT.o:listing.cpp:(.text+0x0): first defined here /tmp/ccCFVTXP.o: In function utils::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 ofutils::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 function utils::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 ofutils::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 function utils::string::prependAndAppendILikeDelimiter(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)': listings.cpp:(.text+0x484): multiple definition ofutils::string::prependAndAppendILikeDelimiter(std::basic_string, std::allocator > const&)' /tmp/cczDtRdT.o:listing.cpp:(.text+0x484): first defined here /tmp/ccifZISK.o: In function utils::string::tolower(std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)': match_count.cpp:(.text+0x0): multiple definition ofutils::string::tolower(std::basic_string, std::allocator >&)' /tmp/cczDtRdT.o:listing.cpp:(.text+0x0): first defined here /tmp/ccifZISK.o: In function utils::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 ofutils::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 function utils::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 ofutils::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 function utils::string::prependAndAppendILikeDelimiter(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)': match_count.cpp:(.text+0x484): multiple definition ofutils::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

Answers (2)

LMC
LMC

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

Kevin Grant
Kevin Grant

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

Related Questions