Structure Binding in visual studio 2017 - visual-studio-2017

I aware that someone asked similar question but what I have seen is different error when I try to use c++17 Structure Binding in my code (e.g. for (auto [i, it] = std::tuple{ 0, nodes.begin() }; i < size; i++)), I have already set to use ISO C++17 Standard (/std:c++17) in project properties and checked compiler version.
Ref: Using c++17 'structured bindings' feature in visual studio 2017
Compiler complained
Error C2429 language feature 'structured bindings' requires compiler flag '/std:c++17'
My Code
TreeNode* ConstructBinaryTree(const int* const intChain, size_t size)
{
std::list<TreeNode*> nodes;
for (auto [i, it] = std::tuple{ 0, nodes.begin() }; i < size; i++)
{
TreeNode* curr = (it != nodes.end())? *it : nullptr;
TreeNode* toBeAssiged = new TreeNode(intChain[i]);
nodes.push_back(toBeAssiged);
if (curr)
{
if (curr->left)
{
curr->right = toBeAssiged;
it++;
}
else
{
curr->left = toBeAssiged;
}
}
}
return (nodes.size() == 0)? nullptr : *nodes.begin();
}
According to https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance?view=vs-2019
Structure binding should be supported after VS 2017 15.3 17
My compiler version

Let's go to the project properties (Alt-F7).
In 'Configuration' field please select: 'All Configurations'.
In 'Platform' field please select: 'All Platforms'.
Click: 'Configuration_Properties->C/C++->Language' and... look at "C++ Language Standard".
Is there: "<different options>" instead of "ISO C++17 Standard..."??
If yes, then change this to C++17 (or later) and compile your project again (MS Visual Studio).
Explanation: Visual Studio have individual properties for all Configuration/Platform combinations. So, it's easy possible to change some detail, which doesn't belong to the current compiler configuration.
It was an issue in my case at least. :-)
My compiler version: 17.2.1 .

Related

Why is my static array[] of my classes failing

I can certainly solve this half a dozen ways but I am curious why what I have coded is not working. (VS 2010 Pro C++)
I have a small class
class Protocol_element
{
public:
const char *Argument;
int EnumID;
int TrueEnum;
int FalseEnum;
bool IsEnabled;
...
It has an explicit ctor:
Protocol_element(const char * arg, int id, int tru, int fals, bool isEnab)
{
Argument = arg;
EnumID = id;
TrueEnum = tru;
FalseEnum = fals;
IsEnabled = isEnab;
{
Then I have an array of addresses of these class elements that is declared static
Protocol_element *Parms::Protocol[] = {
&Protocol_element("SSLV2", GSK_PROTOCOL_SSLV2, GSK_PROTOCOL_SSLV2_ON, GSK_PROTOCOL_SSLV2_OFF, true),
&Protocol_element("SSLV3", GSK_PROTOCOL_SSLV3, GSK_PROTOCOL_SSLV3_ON, GSK_PROTOCOL_SSLV3_OFF, true),
&Protocol_element("TLSV1", GSK_PROTOCOL_TLSV1, GSK_PROTOCOL_TLSV1_ON, GSK_PROTOCOL_TLSV1_OFF, true),
&Protocol_element("TLSV1.1", GSK_PROTOCOL_TLSV1_1, GSK_PROTOCOL_TLSV1_1_ON, GSK_PROTOCOL_TLSV1_1_OFF, false),
&Protocol_element("TLSV1.2", GSK_PROTOCOL_TLSV1_2, GSK_PROTOCOL_TLSV1_2_ON, GSK_PROTOCOL_TLSV1_2_OFF, false),
&Protocol_element("TLSV1.3", GSK_PROTOCOL_TLSV1_3, GSK_PROTOCOL_TLSV1_3_ON, GSK_PROTOCOL_TLSV1_3_OFF, false),
nullptr
};
I can trace with the debugger through the constructors. I can see my whole array get built just as I would expect. But if I breakpoint on int main() the array now is uninitialized storage.
Why? Why did my array "disappear"?
Okay, thanks. I was not sure, but when it compiled, I expected that it might work. As I said, I can think of a dozen ways to solve the problem, and what I have done now, and works, is
Protocol_element Parms::Protocol[] = {
{ "SSLV2", GSK_PROTOCOL_SSLV2, GSK_PROTOCOL_SSLV2_ON, GSK_PROTOCOL_SSLV2_OFF, true },
{ "SSLV3", GSK_PROTOCOL_SSLV3, GSK_PROTOCOL_SSLV3_ON, GSK_PROTOCOL_SSLV3_OFF, true },
{ "TLSV1", GSK_PROTOCOL_TLSV1, GSK_PROTOCOL_TLSV1_ON, GSK_PROTOCOL_TLSV1_OFF, true }, // TODO: Document
{ "TLSV1.1", GSK_PROTOCOL_TLSV1_1, GSK_PROTOCOL_TLSV1_1_ON, GSK_PROTOCOL_TLSV1_1_OFF, false },
{ "TLSV1.2", GSK_PROTOCOL_TLSV1_2, GSK_PROTOCOL_TLSV1_2_ON, GSK_PROTOCOL_TLSV1_2_OFF, false },
{ "TLSV1.3", GSK_PROTOCOL_TLSV1_3, GSK_PROTOCOL_TLSV1_3_ON, GSK_PROTOCOL_TLSV1_3_OFF, false },
nullptr
};
The program is invalid. The address-of operator requires an lvalue.
You are however using a non-standard language extension of a very buggy and outdated compiler. This extension prevents the compiler from yelling at you and refusing to compile the program like the standard (any year) requires. Unfortunately it does not cause the compiler to emit meaningful code. So garbage in, garbage out.
You should upgrade to the latest version of MSVC and use the latest standard (the /std:c++latest flag), or at the very least disable the non-standard extensions with the /Za flag. I cannot guarantee it will help specifically with VS 2010 though, but it does help with modern versions of MSVC.

C++, 'template' keyword before emplace_back(), how does it works?

I was studying Algorithm in C++ using CLion.
I'm currently using Windows 10, Clion 2021.3.3 with bundled MingW
I was working on code, Merge Sort algorithm, and I had chance to use vector.emplace_back().
Whenever I try to use vector.emplace_back() my CLion complier tries to make my code like this.
v.template emplace_back();
I know that Clion is based on Clang-tidy which tries to make my code better and prettier, but how come this code works?
I had no problem or error when I was compiling my code in Clion.
I know that most of us simply just use vector.emplace_back() or vector.push_back(), and it works well in any other IDEs.
I tried to run above usage in both Visual Studio 2022 (C++ 20) and repl.it.
In repl.it, it worked and Visual Studio returned me C2059 syntax error : 'template'.
So I looked up cppreference.com and cplusplus.com to figure out this usage, and neither of them mentioned about this kind of usage.
I do understand that there are some differences between IDEs but it would be great someone who can answer how does my code works.
Below code is my Merge Sort code.
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
template<typename T>
vector<T> merge(vector<T>& arr1, vector<T>& arr2) {
vector<T> merged;
auto iter1 = arr1.begin();
auto iter2 = arr2.begin();
while(iter1 != arr1.end() && iter2 != arr2.end()) {
if (*iter1 < *iter2) {
merged.template emplace_back(*iter1);
iter1++;
}
else {
merged.template emplace_back(*iter2);
iter2++;
}
}
if (iter1 != arr1.end()) {
for (; iter1 != arr1.end(); iter1++)
merged.template emplace_back(*iter1);
}
else {
for (; iter2 != arr2.end(); iter2++)
merged.template emplace_back(*iter2);
}
return merged;
}
template<typename T>
vector<T> merge_sort(vector<T> arr) {
if (arr.size() > 1) {
auto mid = size_t(arr.size() / 2);
auto left = merge_sort<T>(vector<T>(arr.begin(), arr.begin() + mid));
auto right = merge_sort<T>(vector<T>(arr.begin() + mid, arr.end()));
return merge<T>(left, right);
}
return arr;
}
Here is my CMakeList.txt which is nothing special.
cmake_minimum_required(VERSION 3.21)
project(Data)
set(CMAKE_CXX_STANDARD 20)
add_executable(Data main.cpp)
To wrap it up, it would be grateful if someone can tell how does my code works fine, and where should I refer to to to solve my question?
merged.template emplace_back(*iter1);
Respectfully,
I don't know what is wrong with your clang-tidy setup in CLion, but I cannot reproduce the message.
In any case, the message is wrong. The keyword template may be prefixed before a name only if the name is a template-id (except in one case that doesn't matter here), so v.template emplace_back<>(); would be allowed, but v.template emplace_back(); isn't. Some compilers are quite lax of enforcing this rule, so they will accept the version with template prefix as well, but technically that is wrong.
If for some reason you used a template argument list as in merged.template emplace_back<>();, for which there is absolutely no reason on emplace_back, then you would indeed need to add the template prefix, because the type of merged in your code is dependent on the template parameter T and so template is needed to disambiguate the < in the template argument list from being a less-than operator without needing to instantiate the template.

Nested Lambda Capture in C++

I have something like:
// think of Synonym as a set/vector of values
// the purpose of this function is to filter out elements from the 2 synonyms/sets,
// that are not related (similar to SQL inner join) - modifier modifies vars
void Clauses::modifies(Synonym& modifiers, Synonym& modifiedVars, UnaryPredicate isModifies) {
// filter out any modifiers that does not modify (is related to) any of the variables in modifiedVar (left join)
modifiers.removeIf([modifiedVars, &isModifies](int line) -> bool {
return modifiedVars.none([line, &isModifies](int v) -> bool {
return isModifies(line, v);
});
});
// filter out any candidate modifiedVars that is not modified by any modifiers (right join)
modifiedVars.removeIf([modifiers, &isModifies](int varIndex) -> bool {
return modifiers.none([varIndex, &isModifies](int line) -> bool {
return isModifies(line, varIndex);
});
});
// result is an something like an SQL inner join
}
Problem is Visual Studio complains that:
Error 1 error C3480: 'PQL::Clauses::`anonymous-namespace'::<lambda1>::isModifies': a lambda capture variable must be from an enclosing function scope h:\dropbox\sch\cs3202\spa_cpp\spa\pql.cpp 78
Error 2 error C2665: 'PQL::Clauses::`anonymous-namespace'::<lambda3>::<lambda3>' : none of the 2 overloads could convert all the argument types h:\dropbox\sch\cs3202\spa_cpp\spa\pql.cpp 78
...
Originally, the code does not pass the predicates/conditions as references but reading somewhere I thought I needed it, but it didn't seem to change anything
modifiers.removeIf([modifiedVars, isModifies] ...
UPDATE: I am using VS2010 for this project
If you're using Visual Studio 2010, your code could be triggering a bug which doesn't allow you to capture a variable in a nested lambda.
Try using a default capture mode (e.g. [&] instead) as a workaround.
This bug is fixed in VS2012.
It appears to be a Visual C++ bug, as GCC and Clang accept this capture.
Here's a workaround:
modifiedVars.removeIf([modifiers, &isModifies](int varIndex) -> bool {
auto& isModifiesRedirect = isModifies;
return modifiers.none([varIndex, &isModifiesRedirect ](int line) -> bool {
return isModifiesRedirect (line, varIndex);
});
Note: I could only test this on VS2010. It might be fixed in VS2012. You may want to consider searching Microsoft Connect and submitting a new bug if it's not a known issue already.

C++ DLL returning pointer to std::list<std::wstring>

I got a dll with the following prototype:
DLL_EXPORT std::list<std::wstring>* c_ExplodeWStringToList(std::wstring in_delimiter, std::wstring in_string, int in_limit);
The application uses this like that:
std::list<std::wstring>* exploded = mydllclass->c_ExplodeWStringToList(L" ", in_command.c_str(), 0);
This works great under XP 32, but when I try this at home with my Vista 64 my program just closes itself. No error and no warning?
Some days ago the DLL was returning the list directly - no pointer. But I switched to VC++ 2010 Express, and I could not compile my DLL without this modification.
Anything I am not seeing here?
Thank you :)
Update:
DLL_EXPORT std::list<std::wstring>* c_ExplodeWStringToList(std::wstring in_delimiter, std::wstring in_string, int in_limit)
{
std::list<std::wstring>* returnlist = new std::list<std::wstring>();
std::list<std::wstring>* stringlist = new std::list<std::wstring>();
UINT pos = 0;
while(true)
{
pos = in_string.find(in_delimiter, 0);
if(pos == std::string::npos)
{
stringlist->push_back(in_string.substr(0, pos));
break;
}
else
{
stringlist->push_back(in_string.substr(0, pos));
in_string = in_string.substr(pos + in_delimiter.length());
}
}
// ****
// Here is missing some code I've commented out while searching for the error.
// ****
returnlist = stringlist;
return returnlist;
}
T
I didn't dig into the code, but a conclusion I came to regarding working with DLLs is to not return anything but primitive types from DLL functions. This is because due to different compilers or different switches or project settings structs and classes are not aligned the same not have the same size in the DLL and in the code calling the DLL.
So returning a list from a DLL might be considered malformed in the caller application.
Same thing regards throwing exceptions from a DLL - the class thrown might be misinterpreted by the catching code.
So, best is export only C functions that return primitive types (to denote error codes).

_matherr does not get called in release build (C++ Builder 2007)

I have a code with possible floating point overflows which cannot be managed by checking arguments of functions. I have to define _matherr and throw an exception from inside it in order to give a chance to caller to manage the problem.
There is something strange: in Debug build, _matherr is called as supposed, but not in Release. I use CodeGear C++ Builder 2007. Under MSVC 2010 the handler works fine, but I need VCL features for the whole application. Googling gives nothing but messages about _matherr not working in DLL (that is known from documentation).
And my question is: what could be the reason for _matherr to not work in Release?
// One of the methods with overflows.
double DoubleExponential::F(double x) const
{
try
{
double y=pow(fabs(x),a);
return 0.5 + sign(x)*G(y,1/a)/(2*G(1/a));
}
catch(PowExpOverflow)
{
return 0.5;
}
}
// Exception.
struct PowExpOverflow {};
int _matherr (struct _exception *a){
Application->MessageBox("Inside custom _matherr", "", MB_OK);
if (a->type == OVERFLOW)
if (!strcmp(a->name,"pow") ||
!strcmp(a->name,"powl") ||
!strcmp(a->name,"exp") ||
!strcmp(a->name,"expl"))
{
throw PowExpOverflow();
}
return 0;
}
The problem is due to bug in the dynamic RTL which I use in the release build (description). The bug was not fixed in the version of IDE I use, so the only working solution is to upgrade to a higher version. Nevertheless, having a clear explanation helps a lot.