transform compile error in Visual Studio
hmoffatt opened this issue · 11 comments
I'm using transformed
to convert a QVector into a QJsonArray of QJsonObjects as per the code below. It compiles OK with g++ 10 and clang++ 11, but not in Visual Studio 2022.
#include <kdalgorithms.h>
#include <QVector>
#include <QJsonArray>
#include <QJsonObject>
void f()
{
struct S { int a, b; };
QVector<S> s;
auto j = kdalgorithms::transformed<QJsonArray>(s, [](const auto& v)
{
return QJsonObject{
{ QStringLiteral("a"), v.a },
{ QStringLiteral("b"), v.b }
};
});
}
The VS compiler reports
1>test.cpp(973,30): error C2039: 'a': is not a member of 'QJsonValue'
1>C:\qt\Qt5.15.12\5.15.12\msvc2019_64\include\QtCore\qjsonvalue.h(59,21): message : see declaration of 'QJsonValue'
1>C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.34.31933\include\type_traits(1470,1): message : see reference to function template instantiation 'auto f::<lambda_1>::operator ()<QJsonValue>(const _T1 &) const' being compiled
1> with
1> [
1> _T1=QJsonValue
1> ]
1>C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.34.31933\include\type_traits(1675,38): message : see reference to alias template instantiation 'std::_Decltype_invoke_nonzero<f::<lambda_1>,QJsonValue,>' being compiled
1>...\include\kdalgorithms\bits\transform.h(82,19): message : see reference to variable template 'const bool is_invocable_v<`f'::`2'::<lambda_1>,QJsonValue>' being compiled
1>test.cpp(974,30): error C2039: 'b': is not a member of 'QJsonValue'
1>C:\qt\Qt5.15.12\5.15.12\msvc2019_64\include\QtCore\qjsonvalue.h(59,21): message : see declaration of 'QJsonValue'
1>test.cpp(972,22): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'QJsonObject'
1>test.cpp(972,22): message : No constructor could take the source type, or constructor overload resolution was ambiguous
However if I replace the const auto& v
parameter in the lambda with const S& v
then it does compile.
It seems that with auto a QJsonValue is being passed, being the output container's value_type perhaps?
This is indeed odd. Looking at the code on ...\include\kdalgorithms\bits\transform.h(82,19), I see that it is evaluating the requirements of this function:
template <typename InputContainer, typename Transform>
auto transformed(InputContainer &&input, Transform &&transform)
#if __cplusplus >= 202002L
requires std::is_invocable_v<Transform, ValueType>
#endif
but the type you provide as the first template argument (QJsonArray) would make the first argument provided (QVector< S >) not match in the first place, and it should discard this version.
Sorry, this is beyond me.
It works with the compiler set to c++17, but not c++20 or c++2a, which confirms that code is firing. Although I don't understand why it would compile just by removing that is_invocable_v test.
But why is it trying that version of transformed() anyway? It should be the version at line 91 with a different ResultContainer type, since I have explicitly specified a different result container than the input container.
This change has not solved my Visual Studio compile errors. The problem cases are all when the output container is QJsonArray.
Adding the /Zc:__cplusplus
compile flag fixes the build for me. See here for more details.
PR #47 will make adding the flag unnecessary once merged.
Adding the
/Zc:__cplusplus
compile flag fixes the build for me. See here for more details.
I'm afraid it doesn't fix it for me - the code in my report still does not compile. (In fact, qmake in Qt 5.15.12 already enabled that switch for me.)
However if I replace the
const auto& v
parameter in the lambda withconst S& v
then it does compile.
It also works if I specify the return type of the lambda explicitly:
void f()
{
struct S { int a, b; };
QVector<S> s;
auto j = kdalgorithms::transformed<QJsonArray>(s, [](const auto& v) -> QJsonObject
{
return QJsonObject{
{ QStringLiteral("a"), v.a },
{ QStringLiteral("b"), v.b }
};
});
}
I also have a similar problem using filtered_transform
; weirdly, I can use auto
for the transform but not the filter. This compiles:
class ContentItem
{
public:
int num = 0;
int attempt_num = 0;
QDateTime purchased;
QDateTime expires;
};
QVector<ContentItem> user_courses;
auto x = kdalgorithms::filtered_transformed<std::vector<int>>(user_courses,
[](const auto& item) { return item.num; },
[expiry](const ContentItem& item) { return item.expires.isNull() || item.expires >= expiry; });
But using auto
in the filter makes it fail:
auto x = kdalgorithms::filtered_transformed<std::vector<int>>(user_courses,
[](const auto& item) { return item.num; },
[expiry](const auto& item) { return item.expires.isNull() || item.expires >= expiry; });
with error:
1>test.cpp(2685,44): error C2228: left of '.expires' must have class/struct/union
1>test.cpp(2685,44): message : type is 'const _T1'
1> with
1> [
1> _T1=int
1> ]
1>C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.34.31933\include\type_traits(1470,1): message : see reference to function template instantiation 'auto TUser::currentCourseLicences::<lambda_2>::operator ()<_Ty1>(const _T1 &) const' being compiled
1> with
1> [
1> _Ty1=int,
1> _T1=int
1> ]
1>C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.34.31933\include\type_traits(1675,38): message : see reference to alias template instantiation 'std::_Decltype_invoke_nonzero<TUser::currentCourseLicences::<lambda_2>,int,>' being compiled
1>C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.34.31933\include\type_traits(1748,42): message : see reference to alias template instantiation 'std::_Is_invocable_r_<bool,TUser::currentCourseLicences::<lambda_2>,int>' being compiled
1>include\kdalgorithms\bits\shared.h(74,10): message : see reference to variable template 'const bool is_invocable_r_v<bool,`TUser::currentCourseLicences'::`2'::<lambda_2>,int>' being compiled
1>include\kdalgorithms\bits\transform.h(196,14): message : see reference to variable template 'bool UnaryPredicateOnContainerValues<`TUser::currentCourseLicences'::`2'::<lambda_2>,std::vector<int,std::allocator<int> > >' being compiled
Again adding the return types for the lambda makes it compile:
auto x = kdalgorithms::filtered_transformed<std::vector<int>>(user_courses,
[](const auto& item) -> int { return item.num; },
[expiry](const auto& item) -> bool { return item.expires.isNull() || item.expires >= expiry; });
Indeed, the issue with /Zc:__cplusplus
was there but it was unrelated.
I managed to reproduce your error with /std:c++latest
(but not with /std:c++20
somehow).
My impression is that when concepts are introduced that error is legitimate because the requirement that the lambda is invocable with the valuetype or QJsonArray
is met (type-wise auto can be replaced with QJsonValue
just fine, and the body of the lambda is not taken into account with std::is_invocable
). That would explain why it does work when you switch from auto
to S
.
Will have to dig a bit more to figure out more details.
I managed to reproduce your error with
/std:c++latest
(but not with/std:c++20
somehow).
Odd, I have only /std:c++20, not c++latest. Visual Studio 17.4.4 (2022).
Is there another change other than the /Zc:__cplusplus
switch? Because as I wrote above I still have the problem and I thought you were able to reproduce it also.