具有静态 constexpr 成员(函数指针)的模板特化
Template specialization with static constexpr member (function pointer)
我有一个 class 模板,它调用 C 库中的外部函数。根据专业化(主要是 float
和 double
),它应该调用不同的函数。我可以通过模板专业化来实现这一点。下面的代码用 gcc 编译:
// -*- 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
但是如果我尝试使用 clang(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)
我不明白为什么没有实例化特化。有什么想法吗?
clang 在处理静态 constexpr 数据成员时遇到问题。
如果将成员转换为函数,一切都有效。
这里我只是简单地将一个调用运算符应用到代理函数对象上。
#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> {
template<class...Args>
constexpr auto operator()(Args &&... args) const { return sinf(std::forward<Args>(args)...); }
};
template<>
struct Sin_callback<double> {
template<class...Args>
constexpr auto operator()(Args &&... args) const { return sin(std::forward<Args>(args)...); }
};
template<typename T>
class Sin {
T m_arg;
public:
Sin(T &&arg) : m_arg(arg) {}
T calc() {
constexpr Sin_callback<T> m_cb{};
return m_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;
}
预期结果:
ref: 0.84147098480789650665
double: 0.8414709848078965
float: 0.84147095680236816
clang 版本:
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
我有一个 class 模板,它调用 C 库中的外部函数。根据专业化(主要是 float
和 double
),它应该调用不同的函数。我可以通过模板专业化来实现这一点。下面的代码用 gcc 编译:
// -*- 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
但是如果我尝试使用 clang(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)
我不明白为什么没有实例化特化。有什么想法吗?
clang 在处理静态 constexpr 数据成员时遇到问题。
如果将成员转换为函数,一切都有效。
这里我只是简单地将一个调用运算符应用到代理函数对象上。
#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> {
template<class...Args>
constexpr auto operator()(Args &&... args) const { return sinf(std::forward<Args>(args)...); }
};
template<>
struct Sin_callback<double> {
template<class...Args>
constexpr auto operator()(Args &&... args) const { return sin(std::forward<Args>(args)...); }
};
template<typename T>
class Sin {
T m_arg;
public:
Sin(T &&arg) : m_arg(arg) {}
T calc() {
constexpr Sin_callback<T> m_cb{};
return m_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;
}
预期结果:
ref: 0.84147098480789650665
double: 0.8414709848078965
float: 0.84147095680236816
clang 版本:
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