3

I am playing with online c++ compilers a little bit on link. But the code snippet below got failed when compiled with 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
}

How could it be that line #2 is ok and line #1 can't get a pass?

MSVC is happy with the following code but this time it's GCC's turn to reject it. MSVC's iostream file includes cmath header and 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");
}

Since c++20, there's another issue raised in the second answer and has been addressed in this question link

  • Your godbolt link is to the default landing page. You need to choose **share** for a permalink. – StoryTeller - Unslander Monica Nov 12 '21 at 16:11
  • 4
    There is only one `printf` function. `cos` is overloaded and you need to specify which overload you want. – NathanOliver Nov 12 '21 at 16:12
  • Also note that just using `cos` is not portable. `cmath` is not required to expose any functions in the global namespace. If fact, if you make it correct by using `std::cos`, gcc will also fail to compile the code: https://godbolt.org/z/q1q5qcjva – NathanOliver Nov 12 '21 at 16:14
  • `test(static_cast(&std::cos), 0.1);` – Eljay Nov 12 '21 at 16:16
  • @Eljay: Is `cos` in the allowed functions for which we can take address of? – Jarod42 Nov 12 '21 at 16:17
  • @Jarod42 • oooooh.... I don't know, I bet you're right. I can on my compiler, but I wrote my compiler (forked from clang) -- and it's not an intrinsic on mine. And I don't have `::cos` or `::printf` polluting the global namespace either, so I had to add the `std::` for both. It is likely one of those rascally "functions" that can be inlined as a single instruction intrinsic for real compilers versus my Frankenstein's monster compiler. – Eljay Nov 12 '21 at 16:26
  • `test([](double d) { return std::cos(d); }, 0.1);` should mitigate the problem that Jarod42 mentioned. – Eljay Nov 12 '21 at 16:29
  • @Eljay lambda is good, just let the compilers do the deduction. – slow_down_the_pace Nov 12 '21 at 17:05

2 Answers2

2

It is failing because cos is an overloaded function in msvc. This means that there are at least 3 different versions of cos:

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

The compiler has no way of guessing which one you are trying to use, but you can give it a hand by using static_cast like the following:

int main()
{
    test(static_cast<double(*)(double)>(cos), 0.1);
    test(printf, "%s", "aaa");   
}
jdt
  • 336
  • 2
  • 8
  • I am naively thinking that msvc will compile successfully as gcc and clang do :) anyway thanks for the point. by the way, a curious question: why gcc and clang and icc happily go with it even without issuing a warning? – slow_down_the_pace Nov 12 '21 at 17:23
  • @HuFellan, it looks like gcc and clang do not have the overloaded functions. See what happens if you compile the [following](https://tio.run/##ZYsxDsIwDEV3n8ISS4KEegCgdwlOQiMSu2ocdUCcPVTtwMDf3td7NM8Xyo6fvZ8SU24@4C1J1SW4MsLvo@J0GgESKxaX2FiEN@A2L@2RA5qzj43JmoMt3pGkXnEYUKdUcZXlVfcgZnG6@fHwd/zTvYSKLAqf3r8) in gcc and msvc – jdt Nov 12 '21 at 17:41
  • Seems you are right gcc's error shows that cos's prototype is this: double (*)(double) noexcept – slow_down_the_pace Nov 12 '21 at 17:54
  • @HuFellan, it looks like `std::cos` is overloaded in `gcc` but not `cos`. Strange... – jdt Nov 12 '21 at 18:10
  • By reading (https://www.cplusplus.com/reference/cmath/cos/) it's clear that gcc also has its overloads but located in std namespace. A raw cos, gcc regards it as you are referring to the global one: double cos (double x); – slow_down_the_pace Nov 12 '21 at 18:11
  • @HuFellan, sometimes gcc and msvc do not comply with the reference. have a look at this: [https://en.cppreference.com/w/cpp/utility/from_chars](https://en.cppreference.com/w/cpp/utility/from_chars) and then try to use `from_chars` with a double in gcc... – jdt Nov 12 '21 at 18:24
1

It is not allowed to take an address of a library function (with a few exceptions), and thus to pass it as an argument to another function. Any attempt to do so is unspecified behaviour. MSVC is right to reject your program, and gcc is also right to accept it (and perhaps format your hard disk and send nasty emails to your boss).

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243