When I compile and run this with Visual C++ 2010:
#include <iostream>
int main() {
int subtrahend = 5;
struct Subtractor {
int &subtrahend;
int operator()(int minuend) { return minuend - subtrahend; }
} subtractor5 = { subtrahend };
std::cout << subtractor5(47);
}
I get the correct answer, 42.
Nevertheless, the compiler complains that this is impossible:
Temp.cpp(9) : warning C4510: main::Subtractor : default constructor could not be generated
Temp.cpp(6) : see declaration of main::Subtractor
Temp.cpp(9) : warning C4512: main::Subtractor : assignment operator could not be generated
Temp.cpp(6) : see declaration of main::Subtractor
Temp.cpp(9) : warning C4610: struct main::Subtractor can never be instantiated - user defined constructor required
What's going on?
The first two warnings are just letting you know that the implicitly declared member functions cannot be generated due to the presence of a reference data member.
The third warning is a Visual C++ compiler bug.
All three warnings can be ignored with no ill effects, though you can easily make all three go away by making the reference data member a pointer instead (reference data members are almost never worth the trouble).
The first warning is to tell you that a reference value cannot be defaultly constructed(references are guaranteed to point to some value). Switch the subtrahend to a regular integer and the problem will go away.
I am pretty sure the second warning is of similar nature.
(Just saying, it is generally much better to rely on something like boost::function or a similar implementation(std::tr1::function?) instead of writing this code manually)
It's because the variable subtractor5 is an unnamed struct. If you want to make the errors go away, give the structure used for subtractor5 a name.
For example:
struct subtractor {
:
} subtractor5 = { subtrahend };
I unfortunately don't know enough C++ language-ese to know why it works, but I do know why the warning happens.
A user defined constructor is mandatory in following cases:
Initializing constant data members (const int c_member;).
Initializing reference data members (int & r_member;)
Having a data member whose type doesn't have default constructor. Eg:
class NoDefCtor
{
public:
NoDefCtor(int);
};
class ContainThat
{
NoDefCtor no_ctor_member;
};
Inheriting from a base class, where base class doesn't have default constructor. Almost same as above (NoDefCtor).
Related
Sorry for the generic title, but it's a mindfu*k situation, which I can't easily describe.
Suppose the following code:
struct S
{
S() = default;
int x;
int y;
};
S f()
{
return { 1, 2 };
}
This compiles and works perfectly fine. I want to forbid it, as it's bug prone (the actual code is far more complex). So, I tried adding
template<typename T>
S(std::initializer_list<T>) = delete;
but guess what - nothing changes. Tested on Visual Studio 2019 with std=c++17. The C++ resharper shows this as an error, but msvc actually compiles this and it works.
Wait, now it gets interesting. If S() = default; is replaced with S() {}, the compilation fails with
'S::S<int>(std::initializer_list<int>)': attempting to reference a deleted function
OK, this looks like something to do with user-defined constructors and initialization?! Messy, but kinda understandable.
But wait - it gets even more interesting - keeping the = default constructor, but making the fields private also alters this behavior and guess what - the error has nothing to do with inaccessible members, but it again shows the error from above!
So, in order to make this deletion work, I should either make the fields private or define my own empty constructor (ignore the uninitialized x and y fields, this is just a simplified example), meaning:
struct S
{
S() = default;
// S() {}
template<typename T>
S(std::initializer_list<T>) = delete;
private:
int x;
int y;
};
clang 13 and GCC 11 behave exactly the same way, while GCC 9.3 fails to compile the original code (with =default constructor, public fields, but deleted initializer list constructor).
Any ideas what happens?
In C++17, S is considered an aggregate, and because of that you are not calling any constructor, you are basically directly initializing the members. If you change to using C++20, S is no longer considered an aggregate as the rules were changes and the code will work as expected.
The reason changing the access specifier works is that the access specifier of all non-static data members of an aggregate needs to be public. Having them be non-public means your class is no longer an aggregate, and you no longer get aggregate initialization, but instead it tries to do list initialization and fails for the deleted constructor.
I am trying to make a generic class that can represent any object in its most base form, bits. To do this I created a Union of an array of chars (essentially bytes) and the object that the characters make up. Unfortunately when building, I get a strange warning and error for my union.
Warning: "The destructor was implicitly defined as deleted."
Error: "Attempting to reference a deleted function."
(both occur on the line following the definition of my union)
I know that you can create custom destructors for structs, classes and unions, but there is not a need to if you are not freeing up dynamic memory, correct? Yet somehow a destructor I never defined is being automatically called and the compiler deleted it implicitly. Hence the error.
The next thing I attempted was defining a destructor within my union; it did nothing because I never asked the os for additional memory. It was once again deleted. I needed to figure out why the compiler was deleting my function and then causing an error when trying to call it after it deleted it.
I attempted looking for this error in the Microsoft visual studio list, and what it came up with was that not making the constructor public would cause this error. Additionally, looking online here I found that oftentimes the copy constructor is what causes an error because it was never defined. So i tested it by creating a class of my own and using the copy constructor = on it. It worked just fine, but gave me the same error when attempting to use it with my typeAsChar class. Interestingly enough, this error is not called when I use my class with the C default structs, int, double, etc.
Here is the code that causes the issue.
template <class type>
union typeAsChar
{
type obj;
char arr[sizeof(type)];
};
template <class type>
class wontWork
{
public:
wontWork() {/* Do nothing, no data entered */}
wontWork(const type& obj) { foo.obj = obj; }
~wontWork() {/* When this goes out of scope, the default
destructor of the member 'type' should be called */}
typeAsChar<type> foo;
};
int main()
{
double testNum = 12345;
std::string testStr = "Hello World\n";
wontWork<std::string> test1(testStr); // has error
std::cout << test1.foo.obj;
wontWork<double> test2(testNum); // No error
std::cout << test2.foo.obj;
return 0;
}
Oddly enough, this compiles and runs perfectly with wontWork<std::string> commented out, but fails when my class is made with an object of anything other than the standard c structs (int, double, etc). Any clarification on the matter would be much appreciated.
Here is the answer by #Miles Budnek that worked perfectly. Thanks a lot for your info, I never knew that was a functionality in c++.
"reinterpret_cast(&object) is a well-defined way to access the bytes that make up an object (even if it's not very useful for something like std::string). Type-punning via union is not well-defined. – Miles Budnek"
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;
};
So far I have used DEFINE to declare my constants. and it works perfectly fine.
I am trying to use the c++ const keyword in my classes but it gives compile time error
Header
class User{
public:
User::User();
protected:
const float DATA_Z;
}
.CPP
User::User(){
DATA_Z = 0.0023f;
}
this is the error it generates
Error 3 error C2758: 'User::DATA_Z ' : must be initialized in constructor base/member initializer list
How can I assign a data to it, and how can I use them in my class.
The error message is pretty clear. Move assignment into initializer list:
User::User(): DATA_Z(0.0023f)
{
}
You want to do this instead:
User::User() : DATA_Z(0.0023f)
{
// body of constructor
}
Constant members need to be initialized in the initializer list, because they cannot be assigned directly. The same is also true for members that are reference-type, because you cannot change the referent of a reference variable.
To simply replace manifest constants defined with #define, write global consts:
#define DATA_Z 0.0023f
becomes
const float DATA_Z = 0.0023f;
Putting the constants into the class means you can have a different value in each object, which is why the other answers tell you to initialize it in the constructor. That's a legitimate design decision, but it's different from defining the value as a macro.
The following code helps you to pass any value to initialize the DATA_Z:
`
class User{
public:
User::User(float data=0):DATA_Z(data){}; // here `data` is a local parameter to receive the assigned value.
protected:
const float DATA_Z;
}
`
We know that compiler generates some member functions for user-defined class if that member functions are not defined but used, isn't it. So I have this kind of code:
class AA
{
};
void main()
{
AA a;
AA b(a);
a = b;
}
This code works fine. I mean no compiler error. But the following code....
class AA
{
int member1;
int member2;
};
But this code gives an run time error, because variable "a" is used without being iniltialized!!!
So my question is this: when we instantiate an int, it has a value. So why the default constructer doesn't work and by using those two int numbers initializes variable "a"??
EDIT: Platform: Win Vista, Compiler: Visual Studio 2008 compiler; Flags: Default
The compiler-synthesised default constructor calls the default constructors for all class members that have constructors. But integers don't have constructors, and so are not initialised. However, I find it hard to believe that this will cause a run-time error.
To initialise those variables:
class AA {
public:
AA() : member1(0), member2(0) {}
private:
int member1;
int member2;
};
Firstly, from practical point of view this is not a genuine run-time error. This is a built-in debugging feature of your development environment. The compiler attempts to catch situations when your read an uninitialized value, which is exactly what happens in your case.
Secondly, when we "instantiate" an int, it doesn't have a value. More precisely, it contains an undetermined value which is not even guaranteed to be stable (you can get different values by reading the same uninitialized variable several times in a row). Theoretically, reading an uninitialized int variable leads to undefined behavior, since it might contain an illegal ("trap") representation. In fact, you can perceive your "run-time error" generated by your development environment as a manifestation of that undefined behavior.
What platform? compiler? compiler flags? You must have some extra checking being added because there is nothing in normal C++ that checks initialization status.
In fact, the default and copy constructors do work. But in cpp uninitialized variables actually contain garbage. Therefore, you get your error (int member1, int member2 contains trash and you try to assign this trash to b object).
Firstly, When you instantiate an int without initializing it, it has an indeterminate value. A built-in basic type does not have a constructor.
Secondly, that code should not generate a runtime error. It just copies indeterminate int values in the autogenerated copy constructor and assignment operators. It should generate a compiler warning that an uninitialized variable is being used.
Thirdly, your signature for main is wrong - the correct signature is
int main(void)