2017-04-18 169 views
1

我有一個類模板,調用C庫中的外部函數。根據專業化(主要是floatdouble)它應該調用不同的功能。我可以通過模板專業化來實現這一點。模板專精與靜態constexpr成員(函數指針)

// -*- compile-command: "g++ -Wall -Wextra -Werror -pedantic -std=c++14 main.cpp -lm && ./a.out" -*- 

#include <iostream> 

extern "C" { // for illustration: not using cmath, but linking against libm 
    float sinf(float); 
    double sin(double); 
} 

template <typename T> struct Sin_callback; 
template <> struct Sin_callback<float> { static constexpr auto sin_cb = sinf; }; 
template <> struct Sin_callback<double> { static constexpr auto sin_cb = sin; }; 

template <typename T> class Sin{ 
    static constexpr Sin_callback<T> m_cb {}; 
    T m_arg; 
public: 
    Sin(T&& arg): m_arg(arg) {} 
    T calc() { return m_cb.sin_cb(m_arg); } 
}; 

int main(){ 
    Sin<double> dbl(1.0); 
    Sin<float> flt(1.0); 
    std::cout.precision(17); 
    std::cout << "ref:\t0.84147098480789650665" << std::endl; 
    std::cout << "double:\t" << dbl.calc() << std::endl; 
    std::cout << "float:\t" << flt.calc() << std::endl; 
    return 0; 
} 

輸出使用gcc 5.4時:

ref: 0.84147098480789650665 
double: 0.8414709848078965 
float: 0.84147095680236816 

但如果我嘗試編譯此使用鐺(包括3.8和4.0)編譯失敗:

/tmp/main-75afd0.o: In function `Sin<double>::calc()': 
main.cpp:(.text._ZN3SinIdE4calcEv[_ZN3SinIdE4calcEv]+0x14): undefined reference to `Sin_callback<double>::sin_cb' 
/tmp/main-75afd0.o: In function `Sin<float>::calc()': 
main.cpp:(.text._ZN3SinIfE4calcEv[_ZN3SinIfE4calcEv]+0x14): undefined reference to `Sin_callback<float>::sin_cb' 
clang-4.0: error: linker command failed with exit code 1 (use -v to see invocation) 
下面的代碼用gcc編譯

我不明白爲什麼專業化沒有實例化。有任何想法嗎?

回答

2

鏗鏘有靜態constexpr數據成員的問題。

如果您將成員轉換爲函數,它都可以工作。

這裏我簡單地將一個調用操作符應用於代理函數對象。

預計業績:

ref: 0.84147098480789650665 
double: 0.8414709848078965 
float: 0.84147095680236816 

鐺版本:

Apple LLVM version 8.1.0 (clang-802.0.41) 
Target: x86_64-apple-darwin16.5.0 
Thread model: posix 
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin 
+0

非常感謝!變量模板有很大的幫助,因爲我的實際回調函數有大量的參數(函數來自lapack)。只是好奇:你知道我的原始代碼是否符合標準(即這是一個「clang」錯誤)或「未定義」的行爲(在這種情況下,我希望''gcc''來警告我)? –