【问题标题】:Why passing `printf` as template function argument succeeds but `cos` failed (msvc 19)?为什么将`printf`作为模板函数参数传递成功但`cos`失败(msvc 19)?
【发布时间】:2021-12-24 23:23:32
【问题描述】:

我在link 上玩了一点在线 c++ 编译器。但是下面的代码 sn-p 在用 msvc v19.latest 编译时失败了。

#include <iostream>
#include <cmath>
#include <cstdio>

template<class F, class...L>
void test(F f, L...args) {
    std::cout<< "res = " << f(args...) << '\n';
}


int main() 
{
    test(cos, 0.1);   #1
    test(printf, "%s", "aaa");   #2
}

怎么可能2号线没问题,1号线通不过呢?

MSVC 对以下代码很满意,但这次轮到 GCC 拒绝它了。 MSVC 的 iostream 文件包括 cmath 头和 GCC #undefs cos :)

#include <stdio.h>
#include <math.h>
//#include <iostream>

template<class F, class...L>
void test(F f, L...args) {
    f(args...);
}

int main() 
{
    test(cos, 0.1);
    test(printf, "%s", "aaa");
}

从 c++20 开始,第二个答案中提出了另一个问题,并已在此问题中解决link

【问题讨论】:

  • 您的神螺栓链接指向默认登录页面。您需要选择 share 作为永久链接。
  • printf 函数只有一个。 cos 被重载了,你需要指定你想要的重载。
  • 另请注意,仅使用cos 是不可移植的。 cmath 不需要在全局命名空间中公开任何函数。事实上,如果您使用std::cos 使其正确,gcc 也将无法编译代码:godbolt.org/z/q1q5qcjva
  • test(static_cast&lt;double(*)(double)&gt;(&amp;std::cos), 0.1);
  • @Eljay:cos 是否在我们可以获取地址的允许函数中?

标签: c++ visual-c++


【解决方案1】:

not allowed 获取库函数的地址(有一些例外),因此将其作为参数传递给另一个函数。任何这样做的尝试都是未指定的行为。 MSVC 拒绝你的程序是正确的,而 gcc 接受它也是正确的(也许格式化你的硬盘并向你的老板发送讨厌的电子邮件)。

【讨论】:

  • 对于msvc,传printf也行?
  • @HuFellan 标准说它是未指定。特定的编译器可能会说“它实际上没问题”,或者“不,不要那样做”,或者只是什么都不说,让你自己弄清楚。
【解决方案2】:

它失败了,因为cos 是 msvc 中的重载函数。这意味着至少有 3 个不同版本的cos

float cos(float arg);
double cos(double arg);
long double cos(long double arg);

编译器无法猜测您尝试使用哪一个,但您可以使用static_cast 帮助它,如下所示:

int main()
{
    test(static_cast<double(*)(double)>(cos), 0.1);
    test(printf, "%s", "aaa");   
}

【讨论】:

  • 我天真地认为 msvc 将作为 gcc 和 clang 成功编译 :) 无论如何,谢谢你的观点。顺便问一个奇怪的问题:为什么 gcc 和 clang 以及 icc 不发出警告就愉快地使用它?
  • @HuFellan,看起来 gcc 和 clang 没有重载函数。看看如果你在 gcc 和 msvc 中编译 following 会发生什么
  • 看来你是对的gcc的错误说明cos的原型是这样的:double (*)(double) noexcept
  • @HuFellan,看起来std::cosgcc 中超载,但在cos 中没有。奇怪...
  • 通过阅读 (cplusplus.com/reference/cmath/cos) 很明显 gcc 也有其重载,但位于 std 命名空间中。一个原始的 cos,gcc 把它当作你指的是全局的:double cos (double x);
猜你喜欢
  • 2013-03-06
  • 2019-11-16
  • 1970-01-01
  • 2015-04-02
  • 1970-01-01
  • 1970-01-01
  • 2017-06-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多