Are lambdas supposed to be able to see local classes? - c++

The following gives the error 'one': identifier not found in VS2010 and VS2012
int main()
{
struct one {};
[](){ return one(); }();
}
And with a slight tweak...
int main()
{
struct one {};
[](){ one uno; return uno; }();
}
VS2010/VS2012 both have a compiler crash from this code.
So, the question is (ignoring the compiler crash), are lambas supposed to be able to have visibility of local classes?

Yes, VS is incorrect. From 5.1.2p7:
[...] for purposes of name lookup, [...] the compound-statement is considered in the context of the lambda-expression.

Related

When is definition of class' static data member (un/-)necesary

I have a big project and work on refactoring it. Major task is rewrite of logger. New logger is (as far as I can tell) API-compatible with old one, so I believed that after changing header include directory, recompile and relink everything should work. But no. I get multiple errors of the kind undefined reference to <static_data_member>. I can't paste actual code, but it looks for example like this:
// Foo.h
class Foo {
static const int bar = 0;
int baz; // assigned in c-tor
void updateBaz() { baz = bar; }
// ....
}
static const int bar is NOT defined in Foo.cpp. It is sometimes printed by log macros. And it used to work (with old logger), now I have to define it. What change could have caused it?
Another example that that occurs with variables declared by boost:
(...)/blog_adaptor.h:50: error: undefined reference to bbost::serialization::version<CA::CReyzinSignature>::value'
So: when are definitions to static members required and when can they be omitted?
Unless the variables are declared inline (a C++17 feature), definitions of static member variables are not optional, as far as the C++ standard is concerned. Failure to provide a definition is undefined behavior.
Compilers and linkers may vary on exactly what will make them check to see if definitions exist, but that is the nature of undefined behavior.
As Nicol Bolas answered, the code in my project had undefined behavior because static data members were initialized but nowhere defined. To summarize and extend:
Static data member doesn't need to be defined when:
It is not used or is used only in discarded branches (non-instantiated templates and discarded branches of constexpr-if)
in C++17 if member is inline
also clang-tidy says that "out-of-line definition of constexpr static data member is redundant in C++17 and is deprecated", so probably static constexpr also doesn't need it
Further, following code shows why my bad project was not triggering linker error before. I don't know whether it is "not odr-use" or "Undefined Behavior that doesn't hurt you yet":
#include <boost/serialization/version.hpp>
class Klass {};
//BOOST_CLASS_VERSION(Klass, 3);
// would be expanded to:
namespace boost { namespace serialization {
template<>
struct version<Klass> {
static const int value = 3; // not defined anywhere
};
} }
int foo (int val) { // was used by old logger
return val;
}
int bar (const int &val) { // is used by new logger
return val;
}
int main () {
// return bar(boost::serialization::version<Klass>::value); // link error
return foo(boost::serialization::version<Klass>::value); // works fine
}
So there is no link error if member is used but not it's address is not queried. Passing value by reference qualifies as querying the address.

Conflicting overloads with using-declaration

#include <iostream>
struct A {
void test() { std::cout << "A\n"; }
};
struct B : A {
void test() { std::cout << "B\n"; }
};
struct C : B {
using A::test;
using B::test;
};
int main() {
C().test(); // Is this ambiguous?
return 0;
}
In this example, g++ 8.1.0 compiles successfully and calls test() from B.
clang++ 3.8.0 reports: error: call to member function 'test' is ambiguous.
Which is correct? If it is g++, what is the rule that picks B::test over A::test?
I believe Clang is correct.
According to [namespace.udecl]/13:
Since a using-declaration is a declaration, the restrictions on declarations of the same name in the same declarative region ([basic.scope]) also apply to using-declarations.
Since you can't declare two identical member functions, the same applies to using declarations.
GCC lets it compile and test() call becomes the first declaration. In the example given, it'll call the A::test(). But ISO C++ defines it as ambiguous. Visual Studio and clang won't let you compile it. Additionally, this the VS error message: 'B::test': ambiguous call to overloaded function. In my opinion, GCC is wrong by letting it compile.

C++11 private default constructor

The following C++11 code compiles successfully on my GCC 4.8:
struct NonStack
{
private:
NonStack() = default;
public:
static NonStack* Create(){
return new NonStack;
}
};
NonStack a;
int main() { }
However the following gives a compilation error:
struct NonStack
{
private:
NonStack(){}
};
NonStack a;
int main() { }
Why does the first one succeed? Shouldn't the private defaulted constructor prohibit creation of an object via NonStack a;?
This is gcc bug 54812, the compiler fails to respect access specifiers for explicitly defaulted special member functions. Bug 56429, which is marked as a duplicate of the earlier one, has a test case that is almost identical to the example in the question.
The solutions are to upgrade to gcc4.9, which resolves the issue. Or create an empty body for the constructor, instead of explicitly defaulting it, as you've done in the second example.

Obviously ambiguous call does not cause a compilation error on GCC

I was surprised by the fact that GCC does not consider the call to foo() in the following program ambiguous:
#include <iostream>
struct B1 { bool foo(bool) { return true; } };
struct B2 { bool foo(bool) { return false; } };
struct C : public B1, public B2
{
using B1::foo;
using B2::foo;
};
int main()
{
C c;
// Compiles and prints `true` on GCC 4.7.2 and GCC 4.8.0 (beta);
// does not compile on Clang 3.2 and ICC 13.0.1;
std::cout << std::boolalpha << c.foo(true);
}
The above function call compiles and returns true on GCC 4.7.2 and GCC 4.8.0 (beta), while it won't compile (as I would expect) on Clang 3.2 and ICC 13.0.1.
Is this a case of "no diagnostic required", or is it a bug in GCC? References to the C++11 Standard are encouraged.
§7.3.3/3:
In a using-declaration used as a member-declaration, the nested-name-specifier shall name a base class of the class being defined. If such a using-declaration names a constructor, the nested-name-specifier shall name a direct base class of the class being defined; otherwise it introduces the set of declarations found by member name lookup (10.2, 3.4.3.1).
¶14:
… [ Note: Two using-declarations may introduce functions with the same name and the same parameter types. If, for a call to an unqualified function name, function overload resolution selects the functions introduced by such using-declarations, the function call is ill-formed.
¶16:
For the purpose of overload resolution, the functions which are introduced by a using-declaration into a
derived class will be treated as though they were members of the derived class.
So, the using declarations are legal, but the functions are peers in the same overload set, as you said, and the program is ill-formed.
The call to foo(true) in your program is, as you say, clearly ambiguous; furthermore, it is ambiguous according to the algorithm presented in §10.2 and consequently, it should be flagged on use. (Flagging the using declaration would be incorrect; 10.2(1) clearly states that ambiguous uses of names are flagged on lookup, not on declaration.)
It's interesting to contrast this program with a similar one, which is the subject of a a recognized gcc bug (slightly modified from that bug report to make the parallel clearer):
#include <iostream>
struct A {
static int foo() {return 1;}
static int foo(char) { return 2;}
};
struct B1 : A {
// using A::foo;
};
struct B2 : A {
// using A::foo;
};
struct C : B1, B2 {
// using B1::foo;
// using B2::foo;
};
int main()
{
std::cout << C::foo();
}
The above program is correct; despite the diamond inheritance, foo is a static member of A, so it is not ambiguous. In fact, gcc compiles it without trouble. However, uncommenting the two instances of using A::foo, which does not change anything about either foo, causes gcc to produce the oddly reduplicated error noted in the bug report. Uncommenting the two using declarations inside C, which presumably triggers the other bug which is the subject of this question, then masks the static function bug and causes the program to compile again.
clang seems to handle all possible variants of this program, for what it's worth.
Finally, note that an explicitly declared foo(bool) within C (in the original program) will win out over any foo(bool) brought into C's scope by using declarations. I suspect that both of these bugs are the result of bad bookkeeping while trying to keep track of the various function declarations in each class's scope and their individual provenance (as a sequence of using declarations and function declarations).

What are lookup rules when calling function from lambda?

The following example demonstrates the problem I encountered in VC++ 2010:
class Foo
{
template<class T>
static T foo(T t) { return t; }
public:
void test()
{
auto lambda = []() { return foo(1); }; // call to Foo::foo<int>
lambda();
}
};
VC++ produces: error C3861: 'foo': identifier not found
If I qualify the call to foo: Foo::foo(1); then this example compiles with a warning:
warning C4573: the usage of 'Foo::foo' requires the compiler to capture 'this' but the current default capture mode does not allow it
What does the standard say about this case? Should unqualified name be found? Does the qualified name require capturing this?
Microsoft has been seeing this problem reported in a number of cases. See:
Scope Resolution with lambdas interferes with namespace and type resolution
Template resolution in lambdas
As you've found out, explicit resolution allows it to find the name. There is an additional warning about this which is also a compiler error (name resolution doesn't require access to this, though I can see how a compiler implementation might require it) - it's a separate bug though. Microsoft has confirmed this to be a bug and have apparently prepared a fix for the next release.
The following compiles fine. It seems to me that this must just be a VS bug with templates.
struct Foo {
static void foo() {}
void bar() {
auto f = []() { foo(); };
f();
}
};