Templates with generic classes [duplicate] - c++

I have a class with two constructors, one that takes no arguments and one that takes one argument.
Creating objects using the constructor that takes one argument works as expected. However, if I create objects using the constructor that takes no arguments, I get an error.
For instance, if I compile this code (using g++ 4.0.1)...
class Foo
{
public:
Foo() {};
Foo(int a) {};
void bar() {};
};
int main()
{
// this works...
Foo foo1(1);
foo1.bar();
// this does not...
Foo foo2();
foo2.bar();
return 0;
}
... I get the following error:
nonclass.cpp: In function ‘int main(int, const char**)’:
nonclass.cpp:17: error: request for member ‘bar’ in ‘foo2’, which is of non-class type ‘Foo ()()’
Why is this, and how do I make it work?

Foo foo2();
change to
Foo foo2;
You get the error because compiler thinks of
Foo foo2()
as of function declaration with name 'foo2' and the return type 'Foo'.
But in that case If we change to Foo foo2 , the compiler might show the error " call of overloaded ‘Foo()’ is ambiguous".

Just for the record..
It is actually not a solution to your code, but I had the same error message when incorrectly accessing the method of a class instance pointed to by myPointerToClass, e.g.
MyClass* myPointerToClass = new MyClass();
myPointerToClass.aMethodOfThatClass();
where
myPointerToClass->aMethodOfThatClass();
would obviously be correct.

Parenthesis is not required to instantiate a class object when you don't intend to use a parameterised constructor.
Just use Foo foo2;
It will work.

Adding to the knowledge base, I got the same error for
if(class_iter->num == *int_iter)
Even though the IDE gave me the correct members for class_iter. Obviously, the problem is that "anything"::iterator doesn't have a member called num so I need to dereference it. Which doesn't work like this:
if(*class_iter->num == *int_iter)
...apparently. I eventually solved it with this:
if((*class_iter)->num == *int_iter)
I hope this helps someone who runs across this question the way I did.

I was having a similar error, it seems that the compiler misunderstand the call to the constructor without arguments. I made it work by removing the parenthesis from the variable declaration, in your code something like this:
class Foo
{
public:
Foo() {};
Foo(int a) {};
void bar() {};
};
int main()
{
// this works...
Foo foo1(1);
foo1.bar();
// this does not...
Foo foo2; // Without "()"
foo2.bar();
return 0;
}

I ran into a case where I got that error message and had
Foo foo(Bar());
and was basically trying to pass in a temporary Bar object to the Foo constructor. Turns out the compiler was translating this to
Foo foo(Bar(*)());
that is, a function declaration whose name is foo that returns a Foo that takes in an argument -- a function pointer returning a Bar with 0 arguments. When passing in temporaries like this, better to use Bar{} instead of Bar() to eliminate ambiguity.

If you want to declare a new substance with no parameter (knowing that the object have default parameters) don't write
type substance1();
but
type substance;

Certainly a corner case for this error, but I received it in a different situation, when attempting to overload the assignment operator=. It was a bit cryptic IMO (from g++ 8.1.1).
#include <cstdint>
enum DataType
{
DT_INT32,
DT_FLOAT
};
struct PrimitiveData
{
union MyData
{
int32_t i;
float f;
} data;
enum DataType dt;
template<typename T>
void operator=(T data)
{
switch(dt)
{
case DT_INT32:
{
data.i = data;
break;
}
case DT_FLOAT:
{
data.f = data;
break;
}
default:
{
break;
}
}
}
};
int main()
{
struct PrimitiveData pd;
pd.dt = DT_FLOAT;
pd = 3.4f;
return 0;
}
I received 2 "identical" errors
error: request for member ‘i’ [and 'f'] in ‘data’, which is of non-class type ‘float’
(The equivalent error for clang is:
error: member reference base type 'float' is not a structure or union)
for the lines data.i = data; and data.f = data;. Turns out the compiler was confusing local variable name 'data' and my member variable data. When I changed this to void operator=(T newData) and data.i = newData;, data.f = newData;, the error went away.

#MykolaGolubyev has already given wonderful explanation. I was looking for a solution to do somthing like this MyClass obj ( MyAnotherClass() ) but the compiler was interpreting it as a function declaration.
C++11 has braced-init-list. Using this we can do something like this
Temp t{String()};
However, this:
Temp t(String());
throws compilation error as it considers t as of type Temp(String (*)()).
#include <iostream>
class String {
public:
String(const char* str): ptr(str)
{
std::cout << "Constructor: " << str << std::endl;
}
String(void): ptr(nullptr)
{
std::cout << "Constructor" << std::endl;
}
virtual ~String(void)
{
std::cout << "Destructor" << std::endl;
}
private:
const char *ptr;
};
class Temp {
public:
Temp(String in): str(in)
{
std::cout << "Temp Constructor" << std::endl;
}
Temp(): str(String("hello"))
{
std::cout << "Temp Constructor: 2" << std::endl;
}
virtual ~Temp(void)
{
std::cout << "Temp Destructor" << std::endl;
}
virtual String get_str()
{
return str;
}
private:
String str;
};
int main(void)
{
Temp t{String()}; // Compiles Success!
// Temp t(String()); // Doesn't compile. Considers "t" as of type: Temp(String (*)())
t.get_str(); // dummy statement just to check if we are able to access the member
return 0;
}

Related

How to name class identifier in assignment in c++?

From here: Difference between 'struct' and 'typedef struct' in C++?, I found I need class identifier if there is name collision (for example if class name is the same as function name):
#include <iostream>
using namespace std;
class foo
{
public:
foo() {}
operator char const *() const
{
return "class";
}
};
char const *foo()
{
return "function\n";
}
int main()
{
char const *p;
p = class foo(); //this gets error
cout << p << '\n';
return 0;
}
output:
error: expected primary-expression before ‘class’
p = class foo();
What is primary expression here and how can I identify the class instead of the function? I would like it to print class instead of function. How to do so?
One of the possible solutions:
using bar = class foo;
p = bar();
int main()
{
char const *p;
struct foo f;
p = static_cast<char const*>(f);
cout << p << '\n';
return 0;
}
By the way, the answer you link mentions that one can use typedef class foo foo; to trigger a compiler error for a function of same name. Havning a class and a function of same name isn't something desirable, but rather you need to workaround a bit the fact that the language allows it. And don't miss the last paragraph:
I can't imagine why anyone would ever want to hide a class name with a
function or object name in the same scope as the class. The hiding
rules in C were a mistake, and they should not have been extended to
classes in C++. Indeed, you can correct the mistake, but it requires
extra programming discipline and effort that should not be necessary.
If you are in control of either the function or the class you should definitely rename it or place it inside a namespace.
I found two solutions that are accepted by both g++ and clang. I do not know, however, if they are standard C++.
Uniform initialization
cout << (class foo){} << "\n";
Using a helper
template <typename T, typename ...Args>
T ctor(Args&& ...args) {
return T{ std::forward<Args>(args) ... };
}
// ...
cout << ctor<class foo>() << "\n";

Is it safe to cast between a function pointer and a member function pointer? [duplicate]

I've inherited some C++ code and I've been tasked with getting rid of warnings.
Here we have a member function pointer being cast to a function pointer.
I understand that member function pointers are "different" from function pointers, in that there is an implicit 'this' parameter involved under the hood. However my predecessor appears to have made explicit use of this fact, by casting from a member function pointer to a function pointer with an additional first parameter inserted.
My Questions are:
A) Can I get rid of the compiler warning?
B) To what extent is this code guaranteed to work?
I've cut it down to a small main.cpp for the purposes of this question:
#define GENERIC_FUNC_TYPE void(*)(void)
#define FUNC_TYPE int(*)(void *)
class MyClass
{
public:
MyClass(int a) : memberA(a) {}
int myMemberFunc()
{
return memberA;
}
private:
int memberA;
};
int main(int argc, char*argv[])
{
int (MyClass::* memberFunc) () = &MyClass::myMemberFunc;
MyClass myObject(1);
std::cout << (myObject.*memberFunc)() << std::endl;
// All good so far
// Now get naughty, store it away in a very basic fn ptr
void(*myStoredFunction)(void) = (GENERIC_FUNC_TYPE)memberFunc; // Compiler warning
// Reinterpret the fn pointer as a pointer to fn, with an extra object parameter
int (*myExtractedFunction)(void*) = (FUNC_TYPE)myStoredFunction;
// Call it
std::cout << myExtractedFunction(&myObject) << std::endl;
}
The code compiles with one warning under g++, and as intended outputs two 1's:
main.cpp: In function ‘int main(int, char**)’:
main.cpp:27:53: warning: converting from ‘int (MyClass::*)()’ to ‘void (*)()’ [-Wpmf-conversions]
void(*myStoredFunction)(void) = (GENERIC_FUNC_TYPE)memberFunc; // Compiler warning
^
IMHO this code is making assumptions about the underlying mechanisms of the compiler. Or maybe these assumptions are valid for all C++ compilers - Can anyone help?
(In the actual code we're storing a whole bunch of function pointers by name in a map. These functions all have different signatures, which is why they are all cast to the same signature void(*)(void). This is analogous to the myStoredFunction above. They are then cast to the individual signatures at the point of calling, analogous to myExtractedFunction above.)
How about create functions which avoid the cast entirely:
template <typename C, void (C::*M)()>
void AsFunc(void* p)
{
(static_cast<C*>(p)->*M)();
}
then
void (*myExtractedFunction)(void*) = &AsFunc<MyClass, &MyClass::myMemberFunc>;
In C++17, with some traits, you might even have template <auto *M> void AsFunc(void* p) and void(*myStoredFunction)(void*) = &AsFunc<&MyClass::myMemberFunc>;
To answer the question in the title, no, you can't legally cast a pointer-to-member-function to a pointer-to-function. Presumably, that's what the "Compiler warning" on the line with that cast said.
A conforming compiler is required to issue a diagnostic when confronted with ill-formed code (that's a bit oversimplified), and this one did. It gave a warning. Having done that, the compiler is free to do something implementation-specific, which it seems to have done: it compiled the code into something that does what you were hoping for.
Compilers are free to represent pointers to member functions in any way that works, and for non-virtual functions, that could be just a "normal" pointer to function. But try that with a virtual function; I'll bet the consequences are more harsh.
A) Can I get rid of the compiler warning?
Yes - wrap the member function in a call from a static function
(This is a low-tech variant of #Jarod42's template based answer)
B) To what extent is this code guaranteed to work?
It's not (summarizing #Pete Becker's answer). Until you get rid of the warning.
Here's the jist of what we went with. We kept it simple to minimize disruption to the code. We avoided advanced C++ features to maximize the number of people who can work on the code.
#include <iostream>
class MyClass
{
public:
MyClass(int a) : memberA(a) {}
static int myMemberFuncStatic(MyClass *obj)
{
return obj->myMemberFunc();
}
int myMemberFunc()
{
return memberA;
}
private:
int memberA;
};
typedef void(*GENERIC_FUNC_TYPE)(void);
typedef int(*FUNC_TYPE)(MyClass *);
int main(int argc, char*argv[])
{
int (* staticFunc) (MyClass *) = &MyClass::myMemberFuncStatic;
MyClass myObject(1);
std::cout << staticFunc(&myObject) << std::endl;
// All good so far
// This is actually legal, for non-member functions (like static functions)
GENERIC_FUNC_TYPE myStoredFunction = reinterpret_cast<GENERIC_FUNC_TYPE> (staticFunc); // No compiler warning
// Reinterpret the fn pointer as the static function
int (*myExtractedFunction)(MyClass*) = (FUNC_TYPE)myStoredFunction;
// Call it
std::cout << myExtractedFunction(&myObject) << std::endl;
}
Since you apparently need to call a function by name on some "untyped" object (void*) while passing in a number of arguments that differ by function, you need some kind of multiple-dispatch. A possible solution is:
#include <string>
#include <iostream>
#include <stdexcept>
#include <functional>
#include <utility>
#include <map>
template <typename Subj>
using FunctionMap = std::map<std::string, std::function<void (Subj&, const std::string&)>>;
class AbstractBaseSubject {
public:
virtual void invoke (const std::string& fName, const std::string& arg) = 0;
};
template <typename Class>
class BaseSubject : public AbstractBaseSubject {
public:
virtual void invoke (const std::string& fName, const std::string& arg) {
const FunctionMap<Class>& m = Class::functionMap;
auto iter = m.find (fName);
if (iter == m.end ())
throw std::invalid_argument ("Unknown function \"" + fName + "\"");
iter->second (*static_cast<Class*> (this), arg);
}
};
class Cat : public BaseSubject<Cat> {
public:
Cat (const std::string& name) : name(name) {}
void meow (const std::string& arg) {
std::cout << "Cat(" << name << "): meow (" << arg << ")\n";
}
static const FunctionMap<Cat> functionMap;
private:
std::string name;
};
const FunctionMap<Cat> Cat::functionMap = {
{ "meow", [] (Cat& cat, const std::string& arg) { cat.meow (arg); } }
};
class Dog : public BaseSubject<Dog> {
public:
Dog (int age) : age(age) {}
void bark (float arg) {
std::cout << "Dog(" << age << "): bark (" << arg << ")\n";
}
static const FunctionMap<Dog> functionMap;
private:
int age;
};
const FunctionMap<Dog> Dog::functionMap = {
{ "bark", [] (Dog& dog, const std::string& arg) { dog.bark (std::stof (arg)); }}
};
int main () {
Cat cat ("Mr. Snuggles");
Dog dog (7);
AbstractBaseSubject& abstractDog = dog; // Just to demonstrate that the calls work from the base class.
AbstractBaseSubject& abstractCat = cat;
abstractCat.invoke ("meow", "Please feed me");
abstractDog.invoke ("bark", "3.14");
try {
abstractCat.invoke ("bark", "3.14");
} catch (const std::invalid_argument& ex) {
std::cerr << ex.what () << std::endl;
}
try {
abstractCat.invoke ("quack", "3.14");
} catch (const std::invalid_argument& ex) {
std::cerr << ex.what () << std::endl;
}
try {
abstractDog.invoke ("bark", "This is not a number");
} catch (const std::invalid_argument& ex) {
std::cerr << ex.what () << std::endl;
}
}
Here, all classes with functions to be called this way need to derive from BaseSubject (which is a CRTP). These classes (here: Cat and Dog, let's call them "subjects") have different functions with different arguments (bark and meow - of course more than one function per subject is possible). Each subject has its own map of string-to-function. These functions are not function pointers, but std::function<void (SubjectType&,const std::string&)> instances. Each of those should call the respective member function of the object, passing in the needed arguments. The arguments need to come from some kind of generic data representation - here, I chose a simple std::string. It might be a JSON or XML object depending on where your data comes from. The std::function instances need to deserialize the data and pass it as arguments. The map is created as a static variable in each subject class, where the std::function instances are populated with lambdas. The BaseSubject class looks up the function instance and calls it. Since the subject class should always directly derive from BaseSubject<Subject>, pointers of type BaseSubject<Subject>* may be directly and safely cast to Subject*.
Note that there is no unsafe cast at all - it is all handled by virtual functions. Therefore, this should be perfectly portable. Having one map per subject class is typing-intensive, but allows you to have identically-named functions in different classes. Since some kind of data-unpacking for each function individually is necessary anyways, we have individual unpacking-lambdas inside the map.
If a function's arguments are just the abstract data structure, i.e. const std::string&, we could leave the lambdas out and just do:
const FunctionMap<Cat> Cat::functionMap = {
{ "meow", &Cat::meow }
};
Which works by way of std::functions magic (passing this via the 1st argument), which, in contrast to function pointers, is well-defined and allowed. This would be particularly useful if all functions have the same signature. In fact, we could then even leave out the std::function and plug in Jarod42's suggestion.
PS: Just for fun, here's an example where casting a member-function-pointer to an function-pointer fails:
#include <iostream>
struct A {
char x;
A () : x('A') {}
void foo () {
std::cout << "A::foo() x=" << x << std::endl;
}
};
struct B {
char x;
B () : x('B') {}
void foo () {
std::cout << "B::foo() x=" << x << std::endl;
}
};
struct X : A, B {
};
int main () {
void (B::*memPtr) () = &B::foo;
void (*funPtr) (X*) = reinterpret_cast<void (*)(X*)> (memPtr); // Illegal!
X x;
(x.*memPtr) ();
funPtr (&x);
}
On my machine, this prints:
B::foo() x=B
B::foo() x=A
The B class shouldn't be able to print "x=A"! This happens because member-function pointers carry an extra offset that is added to this before the call, in case multiple inheritance comes into play. Casting loses this offset. So, when calling the casted function pointer, this automatically refers to the first base object, while B is the second, printing the wrong value.
PPS: For even more fun:
If we plug in Jarod42's suggestion:
template <typename C, void (C::*M)(), typename Obj>
void AsFunc (Obj* p) {
(p->*M)();
}
int main () {
void (*funPtr) (X*) = AsFunc<B, &B::foo, X>;
X x;
funPtr (&x);
}
the program correctly prints:
B::foo() x=B
If we look at the disassembly of AsFunc, we see:
c90 <void AsFunc<B, &B::foo, X>(X*)>:
c90: 48 83 c7 01 add $0x1,%rdi
c94: e9 07 ff ff ff jmpq ba0 <B::foo()>
The compiler automatically generated code that adds 1 to the this pointer, such that B::foo is called with this pointing to the B base class of X. To make this happen in the AsFunc function (opposed to buried within main), I introduced the Obj template parameter which lets the p argument be of the derived type X such that AsFunc has to do the adding.

C++ Utilizing dot syntax to call function on "Property" (unnamed class)

Goal
My objective is to call StaticLibrary::func() from the property (unnamed class) on Environment using the dot syntax.
For example:
env.bar.func();
I have been able to achieve static_cast<StaticLibrary>(env.bar).func();, which is close, but the syntax is still too cumbersome.
Question
Can the static cast be inferred, or can I overload some operator to get the desired syntax?
NOTE: I have a constraint that I cannot put StaticLibrary directly as a public member of the Environment class (object, reference or pointer).
Error
I currently get the error (which I understand, but pasted here for completeness):
unnamedDotSyntax.cpp: In function ‘int main()’:
unnamedDotSyntax.cpp:48:13: error: ‘class Environment::<anonymous>’ has no member named ‘func’
env.bar.func();
^
Code
The example below is the most distilled version of the code I can offer.
#include <iostream>
class StaticLibrary {
public:
int func (void) {
std::cout << "called " << __FUNCTION__ << std::endl;
}
};
class Environment {
public:
Environment (void) {
bar.sl = &sl;
}
inline
int foo (void) {
std::cout << "called " << __FUNCTION__ << std::endl;
}
class {
friend Environment;
public:
operator StaticLibrary & (void) {
return *sl;
}
private:
StaticLibrary * sl;
} bar;
private:
StaticLibrary sl;
};
int main (void) {
Environment env;
env.foo();
// Works
StaticLibrary sl = env.bar;
sl.func();
// Works, but the syntax is too cumbersome. Can the static cast be inferred somehow?
static_cast<StaticLibrary>(env.bar).func();
// unnamedDotSyntax.cpp:48:13: error: ‘class Environment::<anonymous>’ has no member named ‘func’
// env.bar.func();
env.bar.func();
}
NOTE: This must be GCC compatible not Microsoft VC++
For the nested class there is no way around replicating the interface of StaticLibrary, because the member access operator (.) does not apply any conversions. So to call func() on bar you need to have a member function func() in bar. It does not suffice if bar converts to something that has a member function func() (because this could be ambiguous).
That is to say, you could wrap the interface of StaticLibrary inside bar by having a delegating member function int func() { return sl.func(); } or you make bar a public data member of type StaticLibrary (which was forbidden by your constraint).
Here I gave the nested class a name because it makes the errors more readable and I store a reference rather than a pointer because I like value semantics.
#include <iostream>
class StaticLibrary {
public:
int func() {
std::cout << "called " << __FUNCTION__ << std::endl;
return 0;
}
};
class Environment {
private:
StaticLibrary sl;
public:
class Bar {
friend Environment;
StaticLibrary& sl;
public:
explicit Bar(StaticLibrary& _sl) : sl(_sl) {};
operator StaticLibrary& () { return sl; }
int func() { return sl.func(); }
} bar;
Environment() : sl{}, bar{sl} {};
int foo() {
std::cout << "called " << __FUNCTION__ << std::endl;
return 0;
}
};
int main (void) {
Environment env;
env.foo();
// Works
StaticLibrary sl = env.bar;
sl.func();
// Works, but the syntax is too cumbersome. Can the static cast be inferred somehow?
static_cast<StaticLibrary>(env.bar).func();
// unnamedDotSyntax.cpp:48:13: error: ‘class Environment::<anonymous>’ has no member named ‘func’
// env.bar.func();
env.bar.func();
}

Constructor with bool param allows Java-esque code to compile

This blew my mind today until I realized it only compiles with boolean params.
#include <iostream>
using namespace std;
class Foo {
bool _param;
public:
Foo(bool param) {
_param = param;
}
void say() {
cout << "Param is "<< _param << endl;
}
};
int main() {
Foo foo = new Foo(true);
foo.say();
return 0;
}
I also noticed that the constructor is invoked twice, then my guess is that the pointer created by "new Foo(true)" is being casted to a boolean. Is that it? If so, why it does not work with other parameter types? Is there anything else that I'm not seeing?
Foo foo = new Foo(true);
is equivalent to
Foo foo(new Foo(true));
and the pointer result of new turns into true.
That's why it compiles, and you have a memory leak.
I'll add to πάντα ῥεῖ's answer. The reason it (seemingly) only works with bool, is that pointers could be used since the dawn of c as boolean operands. So the implicit conversion must exist.

For what reason I get the "request for member ... in ... which is of non-class type ..." error in this case? [duplicate]

I have a class with two constructors, one that takes no arguments and one that takes one argument.
Creating objects using the constructor that takes one argument works as expected. However, if I create objects using the constructor that takes no arguments, I get an error.
For instance, if I compile this code (using g++ 4.0.1)...
class Foo
{
public:
Foo() {};
Foo(int a) {};
void bar() {};
};
int main()
{
// this works...
Foo foo1(1);
foo1.bar();
// this does not...
Foo foo2();
foo2.bar();
return 0;
}
... I get the following error:
nonclass.cpp: In function ‘int main(int, const char**)’:
nonclass.cpp:17: error: request for member ‘bar’ in ‘foo2’, which is of non-class type ‘Foo ()()’
Why is this, and how do I make it work?
Foo foo2();
change to
Foo foo2;
You get the error because compiler thinks of
Foo foo2()
as of function declaration with name 'foo2' and the return type 'Foo'.
But in that case If we change to Foo foo2 , the compiler might show the error " call of overloaded ‘Foo()’ is ambiguous".
Just for the record..
It is actually not a solution to your code, but I had the same error message when incorrectly accessing the method of a class instance pointed to by myPointerToClass, e.g.
MyClass* myPointerToClass = new MyClass();
myPointerToClass.aMethodOfThatClass();
where
myPointerToClass->aMethodOfThatClass();
would obviously be correct.
Parenthesis is not required to instantiate a class object when you don't intend to use a parameterised constructor.
Just use Foo foo2;
It will work.
Adding to the knowledge base, I got the same error for
if(class_iter->num == *int_iter)
Even though the IDE gave me the correct members for class_iter. Obviously, the problem is that "anything"::iterator doesn't have a member called num so I need to dereference it. Which doesn't work like this:
if(*class_iter->num == *int_iter)
...apparently. I eventually solved it with this:
if((*class_iter)->num == *int_iter)
I hope this helps someone who runs across this question the way I did.
I was having a similar error, it seems that the compiler misunderstand the call to the constructor without arguments. I made it work by removing the parenthesis from the variable declaration, in your code something like this:
class Foo
{
public:
Foo() {};
Foo(int a) {};
void bar() {};
};
int main()
{
// this works...
Foo foo1(1);
foo1.bar();
// this does not...
Foo foo2; // Without "()"
foo2.bar();
return 0;
}
I ran into a case where I got that error message and had
Foo foo(Bar());
and was basically trying to pass in a temporary Bar object to the Foo constructor. Turns out the compiler was translating this to
Foo foo(Bar(*)());
that is, a function declaration whose name is foo that returns a Foo that takes in an argument -- a function pointer returning a Bar with 0 arguments. When passing in temporaries like this, better to use Bar{} instead of Bar() to eliminate ambiguity.
If you want to declare a new substance with no parameter (knowing that the object have default parameters) don't write
type substance1();
but
type substance;
Certainly a corner case for this error, but I received it in a different situation, when attempting to overload the assignment operator=. It was a bit cryptic IMO (from g++ 8.1.1).
#include <cstdint>
enum DataType
{
DT_INT32,
DT_FLOAT
};
struct PrimitiveData
{
union MyData
{
int32_t i;
float f;
} data;
enum DataType dt;
template<typename T>
void operator=(T data)
{
switch(dt)
{
case DT_INT32:
{
data.i = data;
break;
}
case DT_FLOAT:
{
data.f = data;
break;
}
default:
{
break;
}
}
}
};
int main()
{
struct PrimitiveData pd;
pd.dt = DT_FLOAT;
pd = 3.4f;
return 0;
}
I received 2 "identical" errors
error: request for member ‘i’ [and 'f'] in ‘data’, which is of non-class type ‘float’
(The equivalent error for clang is:
error: member reference base type 'float' is not a structure or union)
for the lines data.i = data; and data.f = data;. Turns out the compiler was confusing local variable name 'data' and my member variable data. When I changed this to void operator=(T newData) and data.i = newData;, data.f = newData;, the error went away.
#MykolaGolubyev has already given wonderful explanation. I was looking for a solution to do somthing like this MyClass obj ( MyAnotherClass() ) but the compiler was interpreting it as a function declaration.
C++11 has braced-init-list. Using this we can do something like this
Temp t{String()};
However, this:
Temp t(String());
throws compilation error as it considers t as of type Temp(String (*)()).
#include <iostream>
class String {
public:
String(const char* str): ptr(str)
{
std::cout << "Constructor: " << str << std::endl;
}
String(void): ptr(nullptr)
{
std::cout << "Constructor" << std::endl;
}
virtual ~String(void)
{
std::cout << "Destructor" << std::endl;
}
private:
const char *ptr;
};
class Temp {
public:
Temp(String in): str(in)
{
std::cout << "Temp Constructor" << std::endl;
}
Temp(): str(String("hello"))
{
std::cout << "Temp Constructor: 2" << std::endl;
}
virtual ~Temp(void)
{
std::cout << "Temp Destructor" << std::endl;
}
virtual String get_str()
{
return str;
}
private:
String str;
};
int main(void)
{
Temp t{String()}; // Compiles Success!
// Temp t(String()); // Doesn't compile. Considers "t" as of type: Temp(String (*)())
t.get_str(); // dummy statement just to check if we are able to access the member
return 0;
}