2014-03-13 45 views
2

我在一個頭文件中定義了一個函數模板,並在幾個源文件中使用它。當我鏈接程序時,出現以下錯誤:內聯函數在鏈接過程中碰撞?

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 

我不明白髮生了什麼事。假設這些函數正在內聯,那麼如何防止跨目標文件的多個實例發生衝突?

這裏是包含函數定義的頭文件:

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 
+1

問題是非模板過載。標記爲「inline」。 – jrok

回答

2

函數模板不是一個問題 - 其定義必須使用存在於每個翻譯單元它們(禁止顯式實例化),由編譯器來安排它,以便鏈接器對它感到滿意。

但是,您還有一個非模板函數,並遵循正常規則。您必須將其定義(= body)移到源文件中,並且只在頭中保留一個聲明,或者將其定義保留在頭中並標記爲inline。當標記爲inline時,它必須再次出現在使用它的每個翻譯單元中(但這正是會發生的情況),並且所有這些都將起作用。