Nested Lambda Capture in C++ - 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.

Related

std::transform applied to data member of sequence's element

Please help me to find a more elegant way to rewrite this snippet using std::transform or similar algorithm:
for (auto& warning : warnings)
{
NormalizePath(warning.path, GetParsedPathLength(warning.path), longestPathLength);
};
Where warning is a struct.
This is what I came up with:
std::transform(begin(warnings), end(warnings), begin(warnings),
[longestPathLength](auto& warning)
{
NormalizePath(warning.path, GetParsedPathLength(warning.path), longestPathLength);
return warning;
});
But it requires a copy of full data-structure. Is there a way to create a modifiable view of a original sequence that contains only path member? So transform could be rewritten only accepting and returning modified path. And in the end all the changes should affect original warnings sequence.
With ranges (C++20), you might "shorter" first version to:
for (auto& path : warnings | std::views::transform(&Warning::path))
{
NormalizePath(path, GetParsedPathLength(path), longestPathLength);
}
You can potentially create some temporary function through lambdas and function bindings:
auto func = [](int size, auto& str){
NormalizePath(str, GetParsedPathLength(str), size);
};
Then call the function with ranges::for_each:
std::ranges::for_each(
warnings, std::bind_front(func, longestPathLength), &warning::path
);
Demo

How does Clang's "did you mean ...?" variable name correction algorithm work?

I am compiling C++ code with Clang. (Apple clang version 12.0.5 (clang-1205.0.22.11)).
Clang can give tips in case you misspell a variable:
#include <iostream>
int main() {
int my_int;
std::cout << my_it << std::endl;
}
spellcheck-test.cpp:5:18: error: use of undeclared identifier 'my_it'; did you mean 'my_int'?
std::cout << my_it << std::endl;
^~~~~
my_int
spellcheck-test.cpp:4:9: note: 'my_int' declared here
int my_int;
^
1 error generated.
My question is:
What is the criterion Clang uses to determine when to suggest another variable?
My experimentation suggests it is quite sophisticated:
If there is another similarly named variable that you might have meant (e.g. int my_in;) it does not give a suggestion
If the suggested variable has the wrong type for the operation (e.g. by trying to print my_it.size() instead) it does not give a suggestion
Whether or not it gives the suggestion depends on a non-trivial comparison of variable names: it allows for both deletions and insertions of characters, and longer variable names allow for more insertion/deletions to be considered "similar".
You will not likely find it documented, but as Clang is open-source you can turn to the source to try to figure it out.
Clangd?
The particular diagnostic (from DiagnosticSemaKinds.td):
def err_undeclared_var_use_suggest : Error<
"use of undeclared identifier %0; did you mean %1?">;
is ever only referred to from clang-tools-extra/clangd/IncludeFixer.cpp:
// Try to fix unresolved name caused by missing declaration.
// E.g.
// clang::SourceManager SM;
// ~~~~~~~~~~~~~
// UnresolvedName
// or
// namespace clang { SourceManager SM; }
// ~~~~~~~~~~~~~
// UnresolvedName
// We only attempt to recover a diagnostic if it has the same location as
// the last seen unresolved name.
if (DiagLevel >= DiagnosticsEngine::Error &&
LastUnresolvedName->Loc == Info.getLocation())
return fixUnresolvedName();
Now, clangd is a language server and t.b.h. I don't know how whether this is actually used by the Clang compiler frontend to yield certain diagnostics, but you're free to continue down the rabbit hole to tie together these details. The fixUnresolvedName above eventually performs a fuzzy search:
if (llvm::Optional<const SymbolSlab *> Syms = fuzzyFindCached(Req))
return fixesForSymbols(**Syms);
If you want to dig into the details, I would recommend starting with the fuzzyFindCached function:
llvm::Optional<const SymbolSlab *>
IncludeFixer::fuzzyFindCached(const FuzzyFindRequest &Req) const {
auto ReqStr = llvm::formatv("{0}", toJSON(Req)).str();
auto I = FuzzyFindCache.find(ReqStr);
if (I != FuzzyFindCache.end())
return &I->second;
if (IndexRequestCount >= IndexRequestLimit)
return llvm::None;
IndexRequestCount++;
SymbolSlab::Builder Matches;
Index.fuzzyFind(Req, [&](const Symbol &Sym) {
if (Sym.Name != Req.Query)
return;
if (!Sym.IncludeHeaders.empty())
Matches.insert(Sym);
});
auto Syms = std::move(Matches).build();
auto E = FuzzyFindCache.try_emplace(ReqStr, std::move(Syms));
return &E.first->second;
}
along with the type of its single function parameter, FuzzyFindRequest in clang/index/Index.h:
struct FuzzyFindRequest {
/// A query string for the fuzzy find. This is matched against symbols'
/// un-qualified identifiers and should not contain qualifiers like "::".
std::string Query;
/// If this is non-empty, symbols must be in at least one of the scopes
/// (e.g. namespaces) excluding nested scopes. For example, if a scope "xyz::"
/// is provided, the matched symbols must be defined in namespace xyz but not
/// namespace xyz::abc.
///
/// The global scope is "", a top level scope is "foo::", etc.
std::vector<std::string> Scopes;
/// If set to true, allow symbols from any scope. Scopes explicitly listed
/// above will be ranked higher.
bool AnyScope = false;
/// The number of top candidates to return. The index may choose to
/// return more than this, e.g. if it doesn't know which candidates are best.
llvm::Optional<uint32_t> Limit;
/// If set to true, only symbols for completion support will be considered.
bool RestrictForCodeCompletion = false;
/// Contextually relevant files (e.g. the file we're code-completing in).
/// Paths should be absolute.
std::vector<std::string> ProximityPaths;
/// Preferred types of symbols. These are raw representation of `OpaqueType`.
std::vector<std::string> PreferredTypes;
bool operator==(const FuzzyFindRequest &Req) const {
return std::tie(Query, Scopes, Limit, RestrictForCodeCompletion,
ProximityPaths, PreferredTypes) ==
std::tie(Req.Query, Req.Scopes, Req.Limit,
Req.RestrictForCodeCompletion, Req.ProximityPaths,
Req.PreferredTypes);
}
bool operator!=(const FuzzyFindRequest &Req) const { return !(*this == Req); }
};
Other rabbit holes?
The following commit may be another leg to start from:
[Frontend] Allow attaching an external sema source to compiler instance and extra diags to TypoCorrections
This can be used to append alternative typo corrections to an existing
diag. include-fixer can use it to suggest includes to be added.
Differential Revision: https://reviews.llvm.org/D26745
from which we may end up in clang/include/clang/Sema/TypoCorrection.h, which sounds like a more reasonably used feature by the compiler frontend than that of the (clang extra tool) clangd. E.g.:
/// Gets the "edit distance" of the typo correction from the typo.
/// If Normalized is true, scale the distance down by the CharDistanceWeight
/// to return the edit distance in terms of single-character edits.
unsigned getEditDistance(bool Normalized = true) const {
if (CharDistance > MaximumDistance || QualifierDistance > MaximumDistance ||
CallbackDistance > MaximumDistance)
return InvalidDistance;
unsigned ED =
CharDistance * CharDistanceWeight +
QualifierDistance * QualifierDistanceWeight +
CallbackDistance * CallbackDistanceWeight;
if (ED > MaximumDistance)
return InvalidDistance;
// Half the CharDistanceWeight is added to ED to simulate rounding since
// integer division truncates the value (i.e. round-to-nearest-int instead
// of round-to-zero).
return Normalized ? NormalizeEditDistance(ED) : ED;
}
used in clang/lib/Sema/SemaDecl.cpp:
// Callback to only accept typo corrections that have a non-zero edit distance.
// Also only accept corrections that have the same parent decl.
class DifferentNameValidatorCCC final : public CorrectionCandidateCallback {
public:
DifferentNameValidatorCCC(ASTContext &Context, FunctionDecl *TypoFD,
CXXRecordDecl *Parent)
: Context(Context), OriginalFD(TypoFD),
ExpectedParent(Parent ? Parent->getCanonicalDecl() : nullptr) {}
bool ValidateCandidate(const TypoCorrection &candidate) override {
if (candidate.getEditDistance() == 0)
return false;
// ...
}
// ...
};
I would recommend checking out this 10-year old blog by Chris Lattner for a general idea of Clang error recovery mechanisms.
On Clang's Spell Checker, he writes:
One of the more visible things that Clang includes is a spell checker (also on reddit). The spell checker kicks in when you use an identifier that Clang doesn't know: it checks against other close identifiers and suggests what you probably meant.
...
Clang uses the well known Levenshtein distance function to compute the best match out of the possible candidates.

no instance of constructor wxTextValidator matches instance

I need to validate text within a wxTextControl as a float or an int (for starters). I will eventually need float > 0, float >= 0 etc etc. My idea was to create an enum defining all of my scenarios and create the val within a function. I'm having trouble getting started, as the declaration of the wxTextValidator throws an error.
enum class glValidate { glInt, glPosInt, gl0PosInt, glFloat, glPosFloat, gl0PosFloat, glString};
wxValidator GuiLib::CreateValidator(std::wstring* default_value, glValidate flag) {
wxArrayString numberArray;
numberArray.Add(wxT("0"));
numberArray.Add(wxT("1"));
numberArray.Add(wxT("2"));
numberArray.Add(wxT("3"));
numberArray.Add(wxT("4"));
numberArray.Add(wxT("5"));
numberArray.Add(wxT("6"));
numberArray.Add(wxT("7"));
numberArray.Add(wxT("8"));
numberArray.Add(wxT("9"));
wxTextValidator val(wxFILTER_NONE, default_value);
switch (flag) {
case glValidate::glInt:
numberArray.Add(wxT("-"));
val.SetStyle = wxFILTER_INCLUDE_LIST;
val.SetIncludes(numberArray);
break;
case glValidate::glPosInt:
val.SetStyle = wxFILTER_INCLUDE_LIST;
val.SetIncludes(numberArray);
break;
}
etc..
}
I recognize that even this simple scenario is busted because the glInt case would allow "123-456", but I think I can deal with that via an event handler once I get this part working. The problem is that I'm getting an error message stating
no instance of constructor "wxTextValidator::wxTextValidator" matches
the argument list
Did you try wxNumValidator< T > instead of your own?
I was fooled by Visual Studio. The problem with the above code is that default_value is wstring, when it needs to be wxString*. Visual Studio highlighted ```wxFILTER_NONE''', which lead me think the problem was there!
After rejigging to make fix the string param it works. Well it compiles - now I need to get the validation working as desired...

question mark in visual studio debugger

I'm using VS 2010 to program in C++.
In debug mode I usually am able to see the content every object/container that I am using, even the ones that comes from the STL. Except that for the following "Entity_set_z_ordered" set, I am unable to see the content of my container, in debug mode it just shows a "?"
struct z_orderer {
bool operator() ( const Entity* lhs, const Entity* rhs) const{
return (lhs->getPosition().y < rhs->getPosition().y || ( (lhs->getPosition().y == rhs->getPosition().y) && lhs->getPosition().x < rhs->getPosition().x));
}
};
std::set<Entity*, z_orderer> Entity_set_z_ordered;
Any idea of where this is coming from or how I could debug this? I haven't changed any of the default Debug setting
thanks
edit : I solved it, the problem was that struct z_orderer was defined inside my main function and not outside of it. I'm not sure if this would have created problems during runtime, but at least I can debug it now!
For anyone else that stumbles across this... this happened to me when I had
a getter property in a class model pointing to itself. It was a copy paste error, notice the property name below is ShouldNotProcess, and in the getter it's returning itself. The return was supposed to be: return !this.ShouldProcess;
public bool ShouldNotProcess
{
get { return !this.ShouldNotProcess; }
}

Syntax for std::binary_function usage

I'm a newbie at using the STL Algorithms and am currently stuck on a syntax error. My overall goal of this is to filter the source list like you would using Linq in c#. There may be other ways to do this in C++, but I need to understand how to use algorithms.
My user-defined function object to use as my function adapter is
struct is_Selected_Source : public std::binary_function<SOURCE_DATA *, SOURCE_TYPE, bool>
{
bool operator()(SOURCE_DATA * test, SOURCE_TYPE ref)const
{
if (ref == SOURCE_All)
return true;
return test->Value == ref;
}
};
And in my main program, I'm using as follows -
typedef std::list<SOURCE_DATA *> LIST;
LIST; *localList = new LIST;;
LIST* msg = GLOBAL_DATA->MessageList;
SOURCE_TYPE _filter_Msgs_Source = SOURCE_TYPE::SOURCE_All;
std::remove_copy(msg->begin(), msg->end(), localList->begin(),
std::bind1st(is_Selected_Source<SOURCE_DATA*, SOURCE_TYPE>(), _filter_Msgs_Source));
What I'm getting the following error in Rad Studio 2010. The error means "Your source file used a typedef symbol where a variable should appear in an expression. "
"E2108 Improper use of typedef 'is_Selected_Source'"
Edit -
After doing more experimentation in VS2010, which has better compiler diagnostics, I found the problem is that the definition of remove_copy only allows uniary functions. I change the function to uniary and got it to work.
(This is only relevant if you didn't accidentally omit some of your code from the question, and may not address the exact problem you're having)
You're using is_Selected_Source as a template even though you didn't define it as one. The last line in the 2nd code snippet should read std::bind1st(is_Selected_Source()...
Or perhaps you did want to use it as a template, in which case you need to add a template declaration to the struct.
template<typename SOURCE_DATA, typename SOURCE_TYPE>
struct is_Selected_Source : public std::binary_function<SOURCE_DATA *, SOURCE_TYPE, bool>
{
// ...
};
At a guess (though it's only a guess) the problem is that std::remove_copy expects a value, but you're supplying a predicate. To use a predicate, you want to use std::remove_copy_if (and then you'll want to heed #Cogwheel's answer).
I'd also note that:
LIST; *localList = new LIST;;
Looks wrong -- I'd guess you intended:
LIST *locallist = new LIST;
instead.