2
votes

An example of what I'm referring to:

#include <type_traits>

void voidFunction() {}

template <typename Function>
void lambdaTest(Function func) {
    [func]() -> void {
        int someInt;
        if constexpr (std::is_same_v<std::invoke_result_t<Function>, int>) {
            someInt = std::invoke(func);
        } else {
            std::invoke(func);
        }
    };
}

int main(int argc, char** argv) {
    lambdaTest(&voidFunction);
    return 0;
}

This compiles in gcc 7.2. However, with MSVC 19.11.25547 I get this error:
error C2440: '=': cannot convert from 'void' to 'int'

This code compiles fine with both compilers:

#include <type_traits>

void voidFunction() {}

template <typename Function>
void nonLambdaTest(Function func) {
    int someInt;
    if constexpr (std::is_same_v<std::invoke_result_t<Function>, int>) {
        someInt = std::invoke(func);
    } else {
        std::invoke(func);
    }
}

int main(int argc, char** argv) {
    nonLambdaTest(&voidFunction);
    return 0;
}

To me it looks like MSVC just ignores the constexpr if. Is this a bug in MSVC, or are constexpr if officially forbidden in lambdas?

1
Probably a compiler bug, this support is brand-new. I guess it works correctly if you have the lambda capture and the constexpr if in separate functions? template <typename Function> void lambdaTest(Function func) { var lambda = [func](){ nonLambdaTest(func) }; lambda(); } - Ben Voigt
Assuming that decltype(Function()) is supposed to yield returned type of function I think that decltype(Function()) is supposed to be decltype(::std::declval<Function>()()) because type of Function would be a pointer to function. So this code seems to be broken in both cases. - user7860670
@VTT - You're right. Sorry, I used invoke_result in my tests and fooled around with decltype and accidentally copied the wrong one. Fixed it in the text - Sebastian.M
I linked to this question from microsofts dev-community: developercommunity.visualstudio.com/content/problem/229226/… - santa

1 Answers

0
votes

I've simplified this example a bit (or at least made it more obvious):

#include <type_traits>
#include <utility>

template<typename TPointerToFunction>
void lambdaTest(TPointerToFunction)
{
    []() -> void // comment this line to make it work
    {
        constexpr const bool returns_int
        {
            std::is_same_v
            <
                int
            ,   decltype(::std::declval<TPointerToFunction>()())
            >
        };
        static_assert(!returns_int);
        if constexpr(returns_int)
        {
            static_assert(returns_int, "how did we get here?");
        }
    };
}

void voidFunction(void) {}

int
main()
{
    lambdaTest(&voidFunction);
    return(0);
}