Why does local struct with in-class initializer hide class' variables? - c++

Consider this code:
class A
{
public:
void f();
private:
int foo;
};
void A::f( )
{
struct S
{
int bar = 100;
} s;
s.bar = foo;
}
This won't compile with VS2013 giving C2327 and C2065 errors on the last line. However, if we delete the initializer or put struct declaration outside this will compile. Is this a bug or standard behavior?
EDIT: Just for the question being complete here are error messages:
error C2327: 'A::foo' : is not a type name, static, or enumerator
error C2065: 'foo' : undeclared identifier

The code is fine with VS2015 RC (ultimate). So VS 2013 has a bug for in class initialization. The following code works for VS 2013
class A
{
public:
void f();
private:
int foo;
};
void A::f( )
{
struct S
{
int bar;
S(int b = 0) : bar{b} {}
} s;
s.bar = foo;
}

Your code is perfectly legal. I would guess that MSVC has a problem with the "new" (i.e. C++11) "in class initializer" int bar = 100;.
Either use a more modern compiler or, if you insist on using MSVC 2013, either write C++98 or be prepared to get random compilation errors for correct code.

Give this a shot.
class A
{
public:
void f();
private:
int foo;
};
void A::f( )
{
struct S
{
int bar;
S() { bar = 100; }
} s;
s.bar = foo;
}
EDIT: Just an FYI, you're trying to initialize a non-const static member in a local class.

Related

Syntax for pointers to a structure

When declaring a pointer to a struct, both the following code snippets compile without error:
A)
struct Foo
{
int data;
Foo* temp; // line in question
}
B)
struct Foo
{
int data;
struct Foo* temp; //line in question
}
What is the significance to repeating the word "struct" in the declaration of the struct pointer (as in (B))? Are there any differences compared to not doing so (as in (A))?
Thank you for your consideration.
In C, struct keyword must be used for declaring structure variables, but it is optional in C++.
For example, consider the following examples:
struct Foo
{
int data;
Foo* temp; // Error in C, struct must be there. Works in C++
};
int main()
{
Foo a; // Error in C, struct must be there. Works in C++
return 0;
}
Example 2
struct Foo
{
int data;
struct Foo* temp; // Works in both C and C++
};
int main()
{
struct Foo a; // Works in both C and C++
return 0;
}
In the above examples, temp is a data member that is a pointer to non-const Foo.

friend injection fails on all compilers except MSVC

Consider the below code.
struct foo {
friend foo create(foo) { return {}; }
};
int main() {
auto a = create(foo{});
return 0;
}
This code compiles perfectly on all compilers.
But the next below code compiles only in MSVC.
struct foo {};
struct bar {
friend bar create(foo) { return {}; }
};
int main() {
auto a = create(foo{});
return 0;
}
Other compilers, such as gcc, clang fail to compile with the following error.
error: 'create' was not declared in this scope
9 | auto a = create(foo{});
Is this non-standard?
I'm working on some template thing, so I must declare the friend function inside of the bar.
Is there any way to achieve it?
See https://en.cppreference.com/w/cpp/language/friend
A name first declared in a friend declaration within a class or class template X becomes a member of the innermost enclosing namespace of X, but is not visible for lookup (except argument-dependent lookup that considers X) unless a matching declaration at the namespace scope is provided - see namespaces for details.
Visual studio is not complying with the standard here, your first version works as the use of foo triggers ADL.
One option is to also declare the function outside the class:
struct foo {};
struct bar {
friend bar create(foo) { return {}; }
};
bar create(foo);
int main() {
auto a = create(foo{});
return 0;
}
Solved with declaring in foo with return type auto.
It only works in C++ >= 14, but compiled in gcc >= 6.0, clang >= 8.0.
struct foo {
friend auto create(foo);
};
struct bar {
friend auto create(foo) { return bar{}; }
};
int main() {
auto a = create(foo{});
return 0;
}

decltype with deleted constructor is possible in template function

As I know decltype is not allowed to use deleted constructor:
struct no_def
{
no_def() = delete;
};
void test()
{
decltype(no_def()) a{}; //error: use of deleted function ‘no_def::no_def()’
}
but if I make template "test" function it will compile
template<typename...>
void test()
{
decltype(no_def()) a{}; //OK
}
and it also
template<typename...>
void test()
{
decltype(no_def("not", "defined", "constructor")) a{}; //OK
}
could someone explain it?
It's apparently a bug in GCC. Both the latest Clang and the latest Visual C++ correctly print a diagnostic message.
Clang:
error: call to deleted constructor of 'no_def'
Visual C++:
error C2280: 'no_def::no_def(void)': attempting to reference a deleted function
You can test this for yourself at https://godbolt.org/.
Note that in order to verify the bug, you should simplify the template, call the function, and get rid of unused-variable warnings which interfere with the output you are interested in:
struct no_def
{
no_def() = delete;
};
template<typename T>
void test()
{
decltype(no_def()) a{}; // error in Clang and MSVC, no error in GCC
a = a; // get rid of warning
}
int main()
{
test<int>();
}

static const int as map subscript

I ran into a strange issue.
Considering this example:
class Foo
{
static const int Bar = 5;
public:
Foo()
{
_map[Bar] = "some characters";
}
~Foo() {}
private:
std::map<int, std::string> _map;
};
int main()
{
Foo a;
return (0);
}
I get this error (compiling with g++ 4.7.2):
/tmp/ccLy806T.o: In function `Foo::Foo()':
Main.cpp:(.text._ZN3FooC2Ev[_ZN3FooC5Ev]+0x1e): undefined reference to `Foo::Bar'
Now, if I make a static_cast on Bar, it works:
Foo()
{
int i = Bar; //works
_map[static_cast<int>(Bar)] = "some characters"; //works
}
This error only appears when using Bar as map subscript in the constructor. Writing _map[Bar] = "some characters"; in an other function in the Foo class doesn't produce any error.
That's really strange for me, but I expect that someone here has an answer.
So, what am I doing wrong ?
That's because map::operator[] takes its key as a int const&. It wants the address of the thing you're passing into it. When you do:
_map[static_cast<int>(Bar)]
you're creating a temporary, and passing in the address to that temporary, which is fine. But when you're doing:
_map[Bar]
Bar doesn't actually have memory storage. You need to provide it via:
class Foo {
....
};
const int Foo::Bar;
You need to add the following at the top level to allocate storage for Foo::Bar:
const int Foo::Bar;

C++: constructor initializer for arrays

I'm having a brain cramp... how do I initialize an array of objects properly in C++?
non-array example:
struct Foo { Foo(int x) { /* ... */ } };
struct Bar {
Foo foo;
Bar() : foo(4) {}
};
array example:
struct Foo { Foo(int x) { /* ... */ } };
struct Baz {
Foo foo[3];
// ??? I know the following syntax is wrong, but what's correct?
Baz() : foo[0](4), foo[1](5), foo[2](6) {}
};
edit: Wild & crazy workaround ideas are appreciated, but they won't help me in my case. I'm working on an embedded processor where std::vector and other STL constructs are not available, and the obvious workaround is to make a default constructor and have an explicit init() method that can be called after construction-time, so that I don't have to use initializers at all. (This is one of those cases where I've gotten spoiled by Java's final keyword + flexibility with constructors.)
Edit: see Barry's answer for something more recent, there was no way when I answered but nowadays you are rarely limited to C++98.
There is no way. You need a default constructor for array members and it will be called, afterwards, you can do any initialization you want in the constructor.
Just to update this question for C++11, this is now both possible to do and very natural:
struct Foo { Foo(int x) { /* ... */ } };
struct Baz {
Foo foo[3];
Baz() : foo{{4}, {5}, {6}} { }
};
Those braces can also be elided for an even more concise:
struct Baz {
Foo foo[3];
Baz() : foo{4, 5, 6} { }
};
Which can easily be extended to multi-dimensional arrays too:
struct Baz {
Foo foo[3][2];
Baz() : foo{1, 2, 3, 4, 5, 6} { }
};
Right now, you can't use the initializer list for array members. You're stuck doing it the hard way.
class Baz {
Foo foo[3];
Baz() {
foo[0] = Foo(4);
foo[1] = Foo(5);
foo[2] = Foo(6);
}
};
In C++0x you can write:
class Baz {
Foo foo[3];
Baz() : foo({4, 5, 6}) {}
};
Unfortunately there is no way to initialize array members till C++0x.
You could use a std::vector and push_back the Foo instances in the constructor body.
You could give Foo a default constructor (might be private and making Baz a friend).
You could use an array object that is copyable (boost or std::tr1) and initialize from a static array:
#include <boost/array.hpp>
struct Baz {
boost::array<Foo, 3> foo;
static boost::array<Foo, 3> initFoo;
Baz() : foo(initFoo)
{
}
};
boost::array<Foo, 3> Baz::initFoo = { 4, 5, 6 };
You can use C++0x auto keyword together with template specialization on for example a function named boost::make_array() (similar to make_pair()). For the case of where N is either 1 or 2 arguments we can then write variant A as
namespace boost
{
/*! Construct Array from #p a. */
template <typename T>
boost::array<T,1> make_array(const T & a)
{
return boost::array<T,2> ({{ a }});
}
/*! Construct Array from #p a, #p b. */
template <typename T>
boost::array<T,2> make_array(const T & a, const T & b)
{
return boost::array<T,2> ({{ a, b }});
}
}
and variant B as
namespace boost {
/*! Construct Array from #p a. */
template <typename T>
boost::array<T,1> make_array(const T & a)
{
boost::array<T,1> x;
x[0] = a;
return x;
}
/*! Construct Array from #p a, #p b. */
template <typename T>
boost::array<T,2> make_array(const T & a, const T & b)
{
boost::array<T,2> x;
x[0] = a;
x[1] = b;
return x;
}
}
GCC-4.6 with -std=gnu++0x and -O3 generates the exact same binary code for
auto x = boost::make_array(1,2);
using both A and B as it does for
boost::array<int, 2> x = {{1,2}};
For user defined types (UDT), though, variant B results in an extra copy constructor, which usually slow things down, and should therefore be avoided.
Note that boost::make_array errors when calling it with explicit char array literals as in the following case
auto x = boost::make_array("a","b");
I believe this is a good thing as const char* literals can be deceptive in their use.
Variadic templates, available in GCC since 4.5, can further be used reduce all template specialization boiler-plate code for each N into a single template definition of boost::make_array() defined as
/*! Construct Array from #p a, #p b. */
template <typename T, typename ... R>
boost::array<T,1+sizeof...(R)> make_array(T a, const R & ... b)
{
return boost::array<T,1+sizeof...(R)>({{ a, b... }});
}
This works pretty much as we expect. The first argument determines boost::array template argument T and all other arguments gets converted into T. For some cases this may undesirable, but I'm not sure how if this is possible to specify using variadic templates.
Perhaps boost::make_array() should go into the Boost Libraries?
This seems to work, but I'm not convinced it's right:
#include <iostream>
struct Foo { int x; Foo(int x): x(x) { } };
struct Baz {
Foo foo[3];
static int bar[3];
// Hmm...
Baz() : foo(bar) {}
};
int Baz::bar[3] = {4, 5, 6};
int main() {
Baz z;
std::cout << z.foo[1].x << "\n";
}
Output:
$ make arrayinit -B CXXFLAGS=-pedantic && ./arrayinit
g++ -pedantic arrayinit.cpp -o arrayinit
5
Caveat emptor.
Edit: nope, Comeau rejects it.
Another edit: This is kind of cheating, it just pushes the member-by-member array initialization to a different place. So it still requires Foo to have a default constructor, but if you don't have std::vector then you can implement for yourself the absolute bare minimum you need:
#include <iostream>
struct Foo {
int x;
Foo(int x): x(x) { };
Foo(){}
};
// very stripped-down replacement for vector
struct Three {
Foo data[3];
Three(int d0, int d1, int d2) {
data[0] = d0;
data[1] = d1;
data[2] = d2;
}
Foo &operator[](int idx) { return data[idx]; }
const Foo &operator[](int idx) const { return data[idx]; }
};
struct Baz {
Three foo;
static Three bar;
// construct foo using the copy ctor of Three with bar as parameter.
Baz() : foo(bar) {}
// or get rid of "bar" entirely and do this
Baz(bool) : foo(4,5,6) {}
};
Three Baz::bar(4,5,6);
int main() {
Baz z;
std::cout << z.foo[1].x << "\n";
}
z.foo isn't actually an array, but it looks about as much like one as a vector does. Adding begin() and end() functions to Three is trivial.
Only the default constructor can be called when creating objects in an array.
In the specific case when the array is a data member of the class you can't initialize it in the current version of the language. There's no syntax for that. Either provide a default constructor for array elements or use std::vector.
A standalone array can be initialized with aggregate initializer
Foo foo[3] = { 4, 5, 6 };
but unfortunately there's no corresponding syntax for the constructor initializer list.
There is no array-construction syntax that ca be used in this context, at least not directly. You can accomplish what you're trying to accomplish by something along the lines of:
Bar::Bar()
{
static const int inits [] = {4,5,6};
static const size_t numInits = sizeof(inits)/sizeof(inits[0]);
std::copy(&inits[0],&inits[numInits],foo); // be careful that there are enough slots in foo
}
...but you'll need to give Foo a default constructor.
Ideas from a twisted mind :
class mytwistedclass{
static std::vector<int> initVector;
mytwistedclass()
{
//initialise with initVector[0] and then delete it :-)
}
};
now set this initVector to something u want to before u instantiate an object. Then your objects are initialized with your parameters.
You can do it, but it's not pretty:
#include <iostream>
class A {
int mvalue;
public:
A(int value) : mvalue(value) {}
int value() { return mvalue; }
};
class B {
// TODO: hack that respects alignment of A.. maybe C++14's alignof?
char _hack[sizeof(A[3])];
A* marr;
public:
B() : marr(reinterpret_cast<A*>(_hack)) {
new (&marr[0]) A(5);
new (&marr[1]) A(6);
new (&marr[2]) A(7);
}
A* arr() { return marr; }
};
int main(int argc, char** argv) {
B b;
A* arr = b.arr();
std::cout << arr[0].value() << " " << arr[1].value() << " " << arr[2].value() << "\n";
return 0;
}
If you put this in your code, I hope you have a VERY good reason.
This is my solution for your reference:
struct Foo
{
Foo(){}//used to make compiler happy!
Foo(int x){/*...*/}
};
struct Bar
{
Foo foo[3];
Bar()
{
//initialize foo array here:
for(int i=0;i<3;++i)
{
foo[i]=Foo(4+i);
}
}
};
in visual studio 2012 or above, you can do like this
struct Foo { Foo(int x) { /* ... */ } };
struct Baz {
Foo foo[3];
Baz() : foo() { }
};
class C
{
static const int myARRAY[10]; // only declaration !!!
public:
C(){}
}
const int C::myARRAY[10]={0,1,2,3,4,5,6,7,8,9}; // here is definition
int main(void)
{
C myObj;
}