【发布时间】:2018-03-15 23:43:28
【问题描述】:
clang 和 gcc 的模板参数解析方式似乎有些不同。或者可能 clang 不考虑 atan2 和 pow 二进制操作,但 gcc 考虑。
下面的代码示例本身没有多大意义,但以最小的方式重现了问题:
#include <vector>
#include <algorithm>
#include <cmath>
#define TRANSFORM_MACRO(op,func) \
template<class T> \
std::vector<T> &trans_##op(const std::vector<T> &a, const std::vector<T> &b, std::vector<T> &dst) { \
std::transform(a.begin(), a.end(), b.begin(), dst.begin(), func); \
return dst; \
} \
template std::vector<float> &trans_##op(const std::vector<float>&, const std::vector<float>&, std::vector<float>&); \
template std::vector<double> &trans_##op(const std::vector<double>&, const std::vector<double>&, std::vector<double>&);
TRANSFORM_MACRO(arctan2, ::atan2)
int main() {
return 0;
}
使用 GCC(5.4 Ubuntu;6.0 OSX Sierra)编译它可以正常工作。使用 clang (900.0.37) 返回以下错误:
/Users/alneuman/CLionProjects/temptest/main.cpp:15:1: error: no matching function for call to 'transform'
TRANSFORM_MACRO(arctan2, atan2)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/.../CLionProjects/temptest/main.cpp:9:7: note: expanded from macro 'TRANSFORM_MACRO'
std::transform(a.begin(), a.end(), b.begin(), dst.begin(), func); \
^~~~~~~~~~~~~~
/Users/.../CLionProjects/temptest/main.cpp:15:1: note: in instantiation of function template specialization 'trans_arctan2<float>' requested here
/Users/.../CLionProjects/temptest/main.cpp:12:34: note: expanded from macro 'TRANSFORM_MACRO'
template std::vector<float> &trans_##op(const std::vector<float>&, const std::vector<float>&, std::vector<float>&); \
^
<scratch space>:22:1: note: expanded from here
trans_arctan2
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/algorithm:1932:1: note: candidate template ignored: couldn't infer template argument '_BinaryOperation'
transform(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2,
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/algorithm:1922:1: note: candidate function template not viable: requires 4 arguments, but 5 were provided
transform(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _UnaryOperation __op)
问题似乎是 GCC 使用了 atan2 和 pow 的内置版本,它们只有一个定义,因此不需要规范。 Clang 似乎回退到具有多个定义的 std::atan2/pow 。 Clang 也有一个 __builtin_atan2,但它不能与 std::transform 一起使用,因为它必须直接调用(考虑编译器输出)。
【问题讨论】:
-
using std::atan2;重现了 gcc 的问题。 atan2 被重载,你需要指定你想要的重载。 -
@MarcGlisse:我认为这为我指明了正确的方向。在原始代码中,
std::transform是宏的一部分(我相应地更新了示例)。如果我像static_cast<T(*)(T, T)>(func)这样在模板中转换func的函数指针,则代码适用于clang但不适用于gcc。 GCC 抱怨invalid static_cast from type 'double(double, double)' to type 'float (*)(float, float)'。看起来 GCC 不知道 atan2 的浮点版本,是吗。 -
将 atan2 替换为
std::atan2以便 gcc 知道浮动版本。 (或atan2f,但你应该包含<math.h>)