使用参数atan2 / pow编译std :: transforms会失败并使用clang(但可以使用gcc)

时间:2017-10-04 14:19:07

标签: xcode c++11 gcc clang++

对于clang和gcc的模板参数的解析方式似乎有些不同。或者,clang不会考虑atan2pow二进制操作,但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使用atan2pow的内置版本,它只有一个定义,因此不需要说明。 Clang似乎回归到std :: atan2 / pow,它有多个定义。 Clang也有一个__builtin_atan2但是这不能和std::transform一起使用,因为它必须直接调用(考虑编译器输出)。

1 个答案:

答案 0 :(得分:0)

感谢@MarcGlisse我想我找出了导致Clang和GCC不同行为的原因。 ::表示法要求在全局名称空间中查找函数。 GCC的atan2 builtin在全局命名空间中具有double签名,但Clang没有。 std version Clang正在使用doublefloat签名的功能。因此,当使用std::atan2时,编译器需要更多特定信息,应使用重载,因为std::atan2具有(至少)三个重载:floatdouble和{ {1}}。这可以通过静态演员实现。使用GCC的内置版本时,long double强制转换显然会失败,因为floatdouble无法静态投放。

我选择float来解决宏观中的含糊不清问题,并且让GCC和Clang使用相同版本的atan2。