使用参数 atan2/pow 编译 std::transforms 失败并发出 clang(但适用于 gcc)
Compiling std::transforms with argument atan2/pow fails with clang (but works with gcc)
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)returns出现如下错误:
/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
一起使用,因为它必须直接调用(考虑编译器输出)。
感谢@MarcGlisse,我想我弄清楚了导致 Clang 和 GCC 行为不同的原因。 ::
符号要求在全局命名空间中查找函数。 GCC 有 atan2
builtin with a double
signature in the global namespace but Clang does not. The std
version Clang 正在使用 double
和 float
签名。因此,当使用 std::atan2
时,编译器需要更具体的信息,因为 std::atan2
具有(至少)三个重载:float
、double
和 long double
。这可以通过静态转换来实现。当使用 GCC 的构建版本时,float
转换显然失败,因为 double
到 float
不能静态转换。
我选择了 TRANSFORM_MACRO(arctan2, static_cast<T(*)(T, T)>(std::atan2))
,它解决了宏中的歧义,并使 GCC 和 Clang 使用相同版本的 atan2。
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)returns出现如下错误:
/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
一起使用,因为它必须直接调用(考虑编译器输出)。
感谢@MarcGlisse,我想我弄清楚了导致 Clang 和 GCC 行为不同的原因。 ::
符号要求在全局命名空间中查找函数。 GCC 有 atan2
builtin with a double
signature in the global namespace but Clang does not. The std
version Clang 正在使用 double
和 float
签名。因此,当使用 std::atan2
时,编译器需要更具体的信息,因为 std::atan2
具有(至少)三个重载:float
、double
和 long double
。这可以通过静态转换来实现。当使用 GCC 的构建版本时,float
转换显然失败,因为 double
到 float
不能静态转换。
我选择了 TRANSFORM_MACRO(arctan2, static_cast<T(*)(T, T)>(std::atan2))
,它解决了宏中的歧义,并使 GCC 和 Clang 使用相同版本的 atan2。