문제

I defined a function template in a header file, and used it in several source files. When I link the program, I get the following errors:

Linking ....................... ./Release_gcc_lin64_5534_ST/tom 
/mxhome/charrison/git/sdcore/libs/CommUtils/Release_gcc_lin64_5534_ST/libCommUtils.so(Block.o): In function `wd_sprintf_r(boost::basic_format<char, std::char_traits<char>, std::allocator<char> > const&)':
/mxhome/charrison/git/sdcore/libs/CommUtils/include/wd_sprintf.h:29: multiple definition of `wd_sprintf_r(boost::basic_format<char, std::char_traits<char>, std::allocator<char> > const&)'
./Release_gcc_lin64_5534_ST/tom.o:/mxhome/charrison/git/sdcore/libs/CommUtils/include/wd_sprintf.h:29: first defined here
/mxhome/charrison/git/sdcore/libs/CommUtils/Release_gcc_lin64_5534_ST/libCommUtils.so(MemRef.o): In function `wd_sprintf_r(boost::basic_format<char, std::char_traits<char>, std::allocator<char> > const&)':
/mxhome/charrison/git/sdcore/libs/CommUtils/include/wd_sprintf.h:29: multiple definition of `wd_sprintf_r(boost::basic_format<char, std::char_traits<char>, std::allocator<char> > const&)'
./Release_gcc_lin64_5534_ST/tom.o:/mxhome/charrison/git/sdcore/libs/CommUtils/include/wd_sprintf.h:29: first defined here

I don't understand what's going on. Presumably the functions are being inlined, so how do I prevent multiple instances across object files from conflicting?

Here is the header file containing the function definition:

wd_sprintf.h:

#ifndef WDSPRINTF_H
#define WDSPRINTF_H

#include <string>
#include <sstream>
#include <boost/format.hpp>

// This is what the recursive template function wd_sprintf_r devolves
// to..
std::string 
wd_sprintf_r(const boost::format &boost_format) {

    std::stringstream s;
    s << boost_format;
    return std::move(s.str()); // force move semantics
}

// wd_sprintf_r(format, args...): 
//
// This unpacks the variadic arguments one at a time, recursively.  It
// binds the first arg to the pattern, and if there are remaining
// variadic arguments, it calls itself.  Otherwise it calls the above.
template <typename T, typename... Params>
std::string 
wd_sprintf_r(boost::format &boost_format, 
         const T &arg, const Params&... parameters) {

    return wd_sprintf_r(boost_format % arg, parameters...); 
}

// wd_sprintf(pattern [,args...]): 
//
// This creates a temporary boost::format from pattern, and calls
// wd_sprintf_r() to recursively extract and apply arguments.

#include <boost/exception/all.hpp>

class wd_sprintf_exception : public std::runtime_error {
public:
    wd_sprintf_exception(std::string const& msg) : std::runtime_error(msg) {};
};

template <typename... Params>
std::string 
wd_sprintf (const std::string &pat, const Params&... parameters) {
    try {
        boost::format boost_format(pat);
        return wd_sprintf_r(boost_format, parameters...);
    }
    catch ( boost::io::format_error& e) {
        const std::string what = std::string("wd_sprintf: ") + std::string(e.what());
        throw wd_sprintf_exception(what);
    }
}

#endif
도움이 되었습니까?

해결책

Function templates are not a problem - their definition must be present in every translation unit using them (barring explicit instantiation), and it is up to the compiler to arrange it so that the linker is happy with it.

However, you also have a non-template function in there, and that follows the normal rules. You must either move its definition (= body) to a source file and keep only a declaration in the header, or keep its definition in the header and mark it inline. When marked inline, it must again be present in every translation unit using it (but that's precisely what will happen), and all will work.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top