1

I have the following code, where I am using a fold expression to evaluate whether all pack parameters are convertible to the first function argument. For some reason it fails to compile on msvc when I make what seems like a very trivial change:

#include <type_traits>

#define TRY 1

#if TRY == 1

template<typename B, typename... Args,
std::enable_if_t<((std::is_convertible_v<Args&, B&> && ...)), bool> = true>
void fn(B b, Args...args) {}

#else

template<typename B, typename... Args,
typename = std::enable_if_t<(std::is_convertible_v<Args&, B&> && ...)>>
void fn(B b, Args...args) {}

#endif

int main()
{
    fn(5, 4, 2);
    return 0;
}

Change TRY to 0 to have it compile, demo at: https://godbolt.org/z/EGvQ-N

Is there an important difference between the two variants that I am missing, or is this a compiler bug?

Stack Danny
  • 7,754
  • 2
  • 26
  • 55
lightxbulb
  • 1,251
  • 12
  • 29
  • 1
    I believe this is a parsing issue with MSVS. There was a Q like this a month or 2 ago I'll try and find and see if that was what was found out – NathanOliver Jul 10 '19 at 20:58
  • Well I found the [post I was thinking of](https://stackoverflow.com/questions/56649481/templated-function-pointer-arrays-in-visual-studio), but it was using an array instead of a fold expression. Might be the same issue or it might not. – NathanOliver Jul 10 '19 at 21:29
  • @NathanOliver That's from a year ago, even if it's the same issue, it would mean that it was either not reported, or they haven't fixed it. I filed a bug report with MS, hopefully they'll fix it. – lightxbulb Jul 10 '19 at 21:34
  • That was from last month. Jun 18 does not mean June of 2018 but June 18th. – NathanOliver Jul 10 '19 at 21:35
  • 1
    It would have Jun 18 '18 if it was from June 18th of last year. – NathanOliver Jul 10 '19 at 21:36
  • @NathanOliver Thank you for clarifying. I guess I am not used to how stack works. – lightxbulb Jul 10 '19 at 21:38

1 Answers1

3

At the risk of being slightly off topic, I'm not sure a fold expression is the best option here. I encourage you to use the std::conjunction variant, which MSVS supports:

- std::enable_if_t<((std::is_convertible_v<Args&, B&> && ...)), bool> = true>
+ std::enable_if_t<std::conjunction_v<std::is_convertible<Args&, B&>...>, bool> = true>

True, it's more verbose, but maybe clearer. I defer to @NathanOliver to track down the potential MSVS bug as originally asked.

(Would have put this as a comment, but thought the code block was clearer.)

KyleKnoepfel
  • 1,426
  • 8
  • 24
  • I was originally trying to get at least something working so that does help quite a bit. I guess I'll file another compiler bug with msvc though (that's the third this week unfortunately). – lightxbulb Jul 10 '19 at 21:15
  • 2
    I have to disagree. I find the fold expression clearer. This is a simple case, and every programmer knows what `&&` is, but "conjunction" takes some thinking and maybe some googling to figure out. IMO, `conjunction` is only really worthwhile when you need its short-circuiting. – Justin Jul 10 '19 at 21:17
  • @Justin Not every programmer knows what a fold expression is either. And if somebody actually doesn't know what conjunction is, it's probably a good idea to look it up either way. My point is that it's subjective which looks better. I prefer the fold simply because I am used to Haskell and I don't like too many `<>`, but that is not to say that it's superior to the other variant imo. – lightxbulb Jul 10 '19 at 21:22