【问题标题】:Compiling std::transforms with argument atan2/pow fails with clang (but works with gcc)使用参数 atan2/pow 编译 std::transforms 失败并出现 clang(但适用于 gcc)
【发布时间】:2018-03-15 23:43:28
【问题描述】:

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 一起使用,因为它必须直接调用(考虑编译器输出)。

【问题讨论】:

  • using std::atan2; 重现了 gcc 的问题。 atan2 被重载,你需要指定你想要的重载。
  • @MarcGlisse:我认为这为我指明了正确的方向。在原始代码中,std::transform 是宏的一部分(我相应地更新了示例)。如果我像static_cast&lt;T(*)(T, T)&gt;(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,但你应该包含&lt;math.h&gt;

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


【解决方案1】:

感谢@MarcGlisse,我想我找到了导致 Clang 和 GCC 行为不同的原因。 :: 表示法要求在全局命名空间中查找函数。 GCC 在全局命名空间中有 atan2 builtindouble 签名,但 Clang 没有。 std version Clang 正在使用 doublefloat 签名。因此,当使用std::atan2 时,编译器需要更具体的信息,因为std::atan2 具有(至少)三个重载:floatdoublelong double。这可以通过静态转换来实现。当使用 GCC 的构建版本时,float 转换显然会失败,因为无法静态转换 doublefloat

我选择了TRANSFORM_MACRO(arctan2, static_cast&lt;T(*)(T, T)&gt;(std::atan2)),它解决了宏中的歧义,也让 GCC 和 Clang 使用相同版本的 atan2。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多