3

I am working with latest version of MSVC, clang and gcc. The two last ones accept the following code, but MSVC rejects it. Is MSVC right? Or is it a bug?

struct A {
  int a, b, c;
};

template <typename T> constexpr auto construct_impl() {
    return [](auto &&... xs) -> decltype(T{xs...}) { return T{xs...}; };
}

int main() {
    auto a = construct_impl<A>()(0, 1, 2);
    return 0;
}
max66
  • 65,235
  • 10
  • 71
  • 111
Antoine Morrier
  • 3,930
  • 16
  • 37
  • 1
    Probably an MSVC bug. In this case, you could just do `-> T`, relying on copy elision, or you could use an explicit type rather than the lambda. Interestingly, turning `construct_impl` into a lambda also lets MSVC compile this – Justin Jun 17 '20 at 22:30
  • I can't do only `-> T` because I want SFINAE to apply here. I transform the inner lambda into a structure and it just works. – Antoine Morrier Jun 17 '20 at 22:34
  • In the example you posted, [removing the return type entirely](https://godbolt.org/z/3s5kCM) also works, if that helps at all. – Paul Sanders Jun 17 '20 at 22:35
  • @PaulSanders as I answered to Justin, I need SFINAE to apply here, so I can't do that :). – Antoine Morrier Jun 17 '20 at 22:41
  • 1
    It compiles for me with `/std:c++latest` – chris Jun 17 '20 at 22:57
  • 2
    @cdhowie No, it's `T`. `T{xs...}` is a prvalue, therefore no reference type is added. It would be very bad if the lambda did return `T&&`, as the constructed value would have to be materialized into a temporary that would bind the returned reference, causing the reference to always be dangling upon the lambda's return and the function to be UB (due to the move construction of the return object) 95% of the time. Also @OP looks like you're missing some `std::forward`s? I would think you want `T{std::forward(xs)...}`. – HTNW Jun 17 '20 at 23:22
  • @HTNW I missed it in the list of prvalues... it's considered a "cast expression" and not a constructor invocation. (I wasn't looking for anything related to casting.) – cdhowie Jun 17 '20 at 23:27
  • For the perfect forwarding, I agree, I just done it quickly, thanks :) – Antoine Morrier Jun 17 '20 at 23:39
  • *"I want SFINAE to apply here"* - May I ask why? Do you compose the lambda with another functor [in something like this](https://stackoverflow.com/a/45020724/817643)? If you do not, then you only ever have a single overload to call, and SFINAE gives you nothing. – StoryTeller - Unslander Monica Jun 24 '20 at 13:12
  • @StoryTeller-UnslanderMonica I made a curry function that works like that : If the function is callable with the given arguments, it calls the function, else, it report the call and save the arguments. So I need to know if the expression is ill formed before we enter the function. But, tbh, in general use case for construction, I don't think I need SFINAE to apply, and it is probably dangerous to have it... :). Maybe it would lead to simpler code and faster to compile code without this SFINAE "trick" I have to think about it, finally, I don't use the construct function in my base code :) – Antoine Morrier Jun 24 '20 at 13:37
  • Here is an example if you want... https://github.com/qnope/Little-Type-Library/blob/master/main.cpp#L1501 https://github.com/qnope/Little-Type-Library/blob/master/include/ltl/functional.h#L94 I needed SFINAE here because of the tuple construction because I want to chain operations like : `vectorOfTuple | map(construct_with_tuple())`, but thanks to your comment, I think it is not necessary finally :), so thanks – Antoine Morrier Jun 24 '20 at 13:42

0 Answers0