Member Initialization in overloaded constructor - c++

I have a basic semantic related doubt that I couldn't able to get clarified. Before stating the problem I will write down the minimum code to explain it clearly.
In Constants.hpp
#pragma once
enum class OpenglESVersion{
OES1,
OES2
};
In Cone.hpp, I have a enum member
OpenglESVersion esVersion;
Overloaded constructor definition in Cone.cpp that takes enum as parameter
Cone::Cone(const OpenglESVersion version) : rotationAngle(0), scale(1), esVersion(version) {}
Now in My RenderingEngine.cpp when i instantiate the Cone object:
Cone cone(OpenglESVersion::OES2);
I get syntax error:
No type named 'OES2' in 'OpenglESVersion'
Now If I update my object instantiaition to:
Cone cone{OpenglESVersion::OES2};
Now it works.
My complier is libc++[LLVM c++ standard library with c++ 11 support]
,and the dialect is c++11[-std=c++11]
I am using XCode.
Now coming to my doubt:
I went through resources to clarify the concept. In past I had use pre c++11 version in school following Bjarne's C++ programming Book which was printed in 2008, so that's why I didn't find this "curly" initialization syntax on the book for c++11 came out later.
I tried google and wasn't sure of what keyword to search but later the most common subject name pointed to "list initialization". Almost every resource covered on the advantage of this new syntax in c++11 but I never got clarified on why normal round bracket is treated as syntax error because there are many resource out there where example shows using rounder bracket too with combination of curly braces while explaining the difference but they were using examples of primitive types like:
int x(4);
int x{4};
So again this was not clarifying the concept for me. Now I am here to know or have some guidance to appropriate link or resource that explain my doubt.
Has my compiler made that round bracket intialization syntax
obsolete?
It's not obsolete but was never supported in c++?
I have declared and defined the overloaded constructor wrongly?
Is initialiation of member not supported via round bracket syntax?
and why?
EDIT:
This happens for any overloaded version, lets say int parameter overloaded version of constructor.
Cone::Cone(const int fooVariable) : fooMember(fooVariable){}
Only code works is:
Cone cone{8};
I get
Expected parameter declarator, Expected ')'
for Cone cone(8);
This behaviour doesn't happen if for curiosity I instantiate inside the member function of Cone class itself like the compiler doesn't thow any syntax or some error:
void Cone::Test(){
Cone cone(OpenglESVersion::OES2);
}
EDIT UPDATE 2:
I think I have another test case which should definitely narrow down. So here is the pattern:
class RenderingEngine
{
private:
Cone cone(OpenglESVersion::OES2);
};
So I am declaring and instantiating the Cone object as a member of RenderingEngine class. So could it be this that is causing my issue? Because If I do
Cone cone(OpenglESVersion::OES2);
inside any member function of RenderingEngine/Outside class implementation then it works. So There must be some basic rule that I am violating on what and how non-primitive member variable can be declared and instantiated.

Member initialization has been introduced in C++11.
Parenthesis are not supported to avoid the most vexing parse, so you can use {..} or = syntax:
class RenderingEngine
{
private:
Cone cone{OpenglESVersion::OES2};
};
or
class RenderingEngine
{
private:
Cone cone = Cone(OpenglESVersion::OES2); // With =, you can use parent on right side
};

Related

Illegal use of this type as an expression when calling template class member

I have a problem with the usage of a static class member size of a class SizeObj, which is used as template parameter for a template class SizeTemplate. See below the code snippet, which I reduced to the minimum.
In fact that code below ran well up to MS VS2008, but now the compilation fails
when compiling with VS2010. The following error messages are displayed:
error C2275: 'K' : illegal use of this type as an expression
error C2228: left of '.size' must have class/struct/union
It need to be said, that the compilation fails only, if the getSize method is
called at least once.
Please don't ask about the sense of the code below, as said I reduced it to the
essential minimum to explain. However, I need to admit that the
usage of the member 'size' is not very elegant due to several reasons, and maybe
there are lots of better solutions, but at the moment, I don't have any choice
to keep it like that.
Do you know what may be wrong here? Is it possible to solve that by build
settings or something similar? I didn't find yet anything suitable yet.
In the following posts it was easy, because an instance of class K is available, but for my problem, I don't know how to get that instance properly:
Illegal use of type in template
Simple templated function to convert std::vectors - "illegal use of this type as an expression"
//myTemplate.h
class SizeObj
{
public:
static const int size = 1;
};
template<class K>
class SizeTemplate
{
public:
int getSize();
};
template<class K>
int SizeTemplate<K>::getSize()
{
return K.size;
}
//main.cpp
int main(...)
{
SizeTemplate<SizeObj> sizeObj;
printf("size:%d", sizeObj.getSize());
}
Thank you a lot in advance!
tangoal
Unlike Java, in C++ you cannot use the dot operator on classes, you need use the scope resolution operator (i.e. ::) to get things from within the class scope (for example the size static variable), so replace return K.size with return K::size
Also marking the method to be constexpr is likely going to help here.

How to define a Struct with default values?

Rather surprised to find this question not asked before. Actually, it has been asked before but the questions are VERY DIFFERENT to mine. They are too complicated and absurd while I'll keep it simple and to the point. That is why this question warrants to be posted.
Now, when I do this,
struct A {
int a = -1;
};
I get the following error:
ANSI C++ forbids in-class initialization of non-const static member a
Now, along with the workaround can someone please tell me THE BEST way of initializing a struct member variable with a default value?
First, let's look at the error:
ANSI C++ forbids in-class initialization of non-const static member a
Initialization of a true instance member, which resides within the memory of an instance of your struct is the responsibility of this struct's constructor.
A static member, though defined inside the definition of a particular class/struct type, does not actually reside as a member of any instances of this particular type. Hence, it's not subject to explaining which value to assign it in a constructor body. It makes sense, we don't need any instances of this type for the static member to be well-initialized.
Normally, people write member initialization in the constructor like this:
struct SomeType
{
int i;
SomeType()
{
i = 1;
}
}
But this is actually not initialization, but assignment. By the time you enter the body of the constructor, what you've done is default-initialize members. In the case of a fundamental type like an int, "default-initialization" basically boils down to "eh, just use whatever value was in those bytes I gave you."
What happens next is that you ask i to now adopt the value 1 via the assignment operator. For a trivial class like this, the difference is imperceptible. But when you have const members (which obviously cannot be tramped over with a new value by the time they are built), and more complex members which cannot be default-initialized (because they don't make available a visible constructor with zero parameters), you'll soon discover you cannot get the code to compile.
The correct way is:
struct SomeType
{
int i;
SomeType() : i(1)
{
}
}
This way you get members to be initialized rather than assigned to. You can initialize more than one by comma-separating them. One word of caution, they're initialized in the order of declaration inside your struct, not how you order them in this expression.
Sometimes you may see members initialized with braces (something like i{1} rather i(c)). The differences can be subtle, most of the time it's the same, and current revisions of the Standard are trying to smooth out some wrinkles. But that is all outside the scope of this question.
Update:
Bear in mind that what you're attempting to write is now valid C++ code, and has been since ratification of C++11. The feature is called "Non-static data member initializers", and I suspect you're using some version of Visual Studio, which still lists support as "Partial" for this particular feature. Think of it as a short-hand form of the member initialization syntax I described before, automatically inserted in any constructor you declare for this particular type.
You could make a default constructor
struct A {
A() : a{-1} {}
int a;
};

C++ template compilation error - recursive type or function dependency

I wrote a template class which is giving compilation error
template<class T>
class Entity
{
string EntityName;
int EntitySize;
Entity<T*> pPrev;
Entity<T*> pNext;
public:
Entity<T>(const string & name, int size)
{
EntityName = name;
EntitySize = size;
}
//member functions
};
I am using MSVC++ 2008, and the error is :
fatal error C1202: recursive type or
function dependency context too
complex
I have not written any recursive function in my class. Then why this error? Please help.
Alright. I'm explaining you the problem you're facing. But first thing first. You said:
I wrote a template class which is
giving compilation error
First of all, as far as C++ is concerned, there is no such thing as a "template class," there is only a "class template." The way to read that phrase is "a template for a class," as opposed to a "function template," which is "a template for a function." Again: classes do not define templates, templates define classes (and functions).* Quoted from here.
Now, lets see the error:
fatal error C1202: recursive type or
function dependency context too
complex
The error says it all. $14.7.1 from the Standard explains the cause of your problem very well, giving you even an example which is very much close to what you're doing. So I don't even need to write a single word of my own. Here is $14.7.1
4 There is an implementation-defined
quantity that specifies the limit on
the total depth of recursive
instantiations, which
could involve more than one template. The result of an infinite
recursion in instantiation is
undefined. [ Example:
template < class T > class X {
X<T >* p; // OK
X<T*> a; //implicit generation of X<T> requires
//the implicit instantiation of X<T*> which requires
//the implicit instantiation of X<T**> which ...
};
—end example ]
Please read the comment with X<T*> a, which is pretty much the case with you too. So your problem is not because of recursive function, it's rather because of recursive instantiation of class template, causing from these lines:
Entity<T*> pPrev;
Entity<T*> pNext;
Hope, it solves your problem!
EDIT : But I'm wondering what are you trying to achieve with Entity<T*> pPrev? It seems its a typo, and you probably wanted to write Entity<T>* pPrev. Same with pNext. Is that so?
And an advice to improve the design : Use Member Initialization list, instead of Assignment. That is, write your constructor the following way,
Entity<T>(const string & name, int size) : EntityName(name), EntitySize(size)
{
//all assignments moved to initialization list.
}
Read this : Why should I prefer to use member initialization list?
Read the error message more closely. The "too complex" thing is not a recursive function, it's a recursive type or function dependency. The type Entity<T*> depends on the type Entity<T>, recursively. When the compiler tries to generate the code for Entity<int>, it will have to figure out Entity<int*> (in order to implement the pPrev and pNext members), which means it will have to figure out Entity<int**>, etc. - infinitely. That isn't allowed.
But that's just how the compiler knows something is wrong. It doesn't know what is wrong, because it can't think about how to program. (If it could, it would just write your program for you.)
The logical error is that Entity<T*> means "an object which is an Entity with template type pointer-to-T". What you really wanted, in order to make a linked list, is "a pointer to an object which is an Entity with template type T". That is spelled Entity<T>*, with the * outside the angle brackets.
But the real problem is that you are trying to create your own linked list. Don't do that. Use the standard library containers. If you're smart enough to use std::string, you should be smart enough to use the containers (std::vector, std::list, etc. - in a sense, std::string is a container, too, albeit a very special-purpose one) too.
Your template definition is infinitely recursive. You define template class Entity<T> that contains objects of type Entity<T*> as members. Objects Entity<T*> will, according to the same definition, contain objects of type Entity<T**>. The latter will in turn contain objects of type Entity<T***> and so on, as infinitum. In other words, your infinitely recursive template definition makes no sense.
Either terminate the recursion or think about what it is you are really trying to implement. I strongly suspect that your member definitions were supposed to have type Entity<T>*, not Entity<T*>.
Change
Entity<T*> pPrev;
Entity<T*> pNext;
to
Entity<T> *pPrev;
Entity<T> *pNext;
Your type definition is recursive...
You have written a recursive type. Entity has other Entity members. You should change the Entity members into a pointer or reference.

C++ Constructor initialization list strangeness

I have always been a good boy when writing my classes, prefixing all member variables with m_:
class Test {
int m_int1;
int m_int2;
public:
Test(int int1, int int2) : m_int1(int1), m_int2(int2) {}
};
int main() {
Test t(10, 20); // Just an example
}
However, recently I forgot to do that and ended up writing:
class Test {
int int1;
int int2;
public:
// Very questionable, but of course I meant to assign ::int1 to this->int1!
Test(int int1, int int2) : int1(int1), int2(int2) {}
};
Believe it or not, the code compiled with no errors/warnings and the assignments took place correctly! It was only when doing the final check before checking in my code when I realised what I had done.
My question is: why did my code compile? Is something like that allowed in the C++ standard, or is it simply a case of the compiler being clever? In case you were wondering, I was using Visual Studio 2008
Yes, it's valid. The names in the member initializer list are looked up in the context of the constructor's class so int1 finds the name of member variable.
The initializer expression is looked up in the context of the constructor itself so int1 finds the parameter which masks the member variables.
What you have done is standard C++. Only member variables or base classes may be initliazed in the initialization list, so the variable outside the paranthesis is unambiguous. Within the parenthesis, the typical scoping rules apply, and the members are overshadowed by the parameter names.
This is perfectly normal behavior. As AAT rightly pointed out, there is no ambiguity. The variables initialised by the list have to be class members. This is standard and works across all compliant compilers.
The only thing to remember while using a list like this is that a person who doesn't understand this kind of code may have to maintain it. There is nothing wrong with writing initialisation code like this as long as you know what you are doing.
I imagine this works because you were using int1 in the initialiser list, and the only things you can initialise are member variables => it was in fact unambiguous which variable was being initialised.
Whether all C++ compilers would be this forgiving is another matter!
What you have done is normal. This kind of implementation avoids you from even using the 'this' pointer (in this case).

Object construction/Forward function declaration ambiguity

Observation: the codes pasted below were tested only with GCC 4.4.1, and I'm only interested in them working with GCC.
Hello,
It wasn't for just a few times that I stumbled into an object construction statement that I didn't understand, and it was only today that I noticed what ambiguity was being introduced by it. I'll explain how to reproduce it and would like to know if there's a way to fix it (C++0x allowed). Here it goes.
Suppose there is a class whose constructor takes only one argument, and this one argument's type is another class with a default constructor. E.g.:
struct ArgType {};
class Class
{
public:
Class(ArgType arg);
};
If I try to construct an object of type Class on the stack, I get an ambiguity:
Class c(ArgType()); // is this an object construction or a forward declaration
// of a function "c" returning `Class` and taking a pointer
// to a function returning `ArgType` and taking no arguments
// as argument? (oh yeh, loli haets awkward syntax in teh
// saucecode)
I say it's an object construction, but the compiler insists it's a forward declaration inside the function body. For you who still doesn't get it, here is a fully working example:
#include <iostream>
struct ArgType {};
struct Class {};
ArgType func()
{
std::cout << "func()\n";
return ArgType();
}
int main()
{
Class c(ArgType());
c(func); // prints "func()\n"
}
Class c(ArgType funcPtr()) // Class c(ArgType (*funcPtr)()) also works
{
funcPtr();
return Class();
}
So well, enough examples. Anyone can help me get around this without making anything too anti-idiomatic (I'm a library developer, and people like idiomatic libraries)?
-- edit
Never mind. This is a dupe of Most vexing parse: why doesn't A a(()); work?.
Thanks, sbi.
This is known as "C++'s most vexing parse". See here and here.
Let's simplify a little.
int f1();
What's that? The compiler (and I) say it's a forward declaration for a function returning an integer.
How about this?
int f2(double );
The compiler (and I) say it's a forward declaration for a function taking a double argument and returning an int.
So have you tried this:
ClassType c = ClassType(ArgType());
Check out the c++ faq lite on constructors for explanations and examples
Based on the "C++0x allowed", the right answer is (probably) to change the definition to:
Class c(ArgType {});
Simple, straightforward and puts the burden entirely on the user of the library, not the author!
Edit: Yes, the ctor is invoked -- C++ 0x adds List-Initialization as an unambiguous way to delimit initializer lists. It can't be mis-parsed like in your sample, but otherwise the meaning is roughly the same as if you used parentheses. See N3000, the third bullet point under §8.5.4/3. You can write a ctor to receive an initializer list as a single argument, or the items in the initializer list can be matched up with the ctor arguments individually.