Templated constructor behaviour

  • Thread starter Ioannis Papadopoulos
  • Start date
I

Ioannis Papadopoulos

Hi,

I have the following code:

#include <iostream>

int foo() {
std::cout << __func__ << std::endl;
}

struct func {
void operator()() {
std::cout << __func__ << std::endl;
}
};

class run {
private:
public:
run() {
std::cout << "THIS SHOULD NOT HAVE BEEN CALLED 1" << std::endl;
}
run(const run&) {
std::cout << "THIS SHOULD NOT HAVE BEEN CALLED 2" << std::endl;
}

template<typename Functor>
run(Functor f) {
std::cout << "CALLED" << std::endl;
f();
}
};

int main() {
run(foo);
run(func());
return 0;
}

My output is:
THIS SHOULD NOT HAVE BEEN CALLED 1

and clearly not what I expected. Any hints?

Thanks
 
N

Neelesh Bodas

Hi,

I have the following code:

#include <iostream>

int foo() {
std::cout << __func__ << std::endl;

}

struct func {
void operator()() {
std::cout << __func__ << std::endl;
}

};

class run {
private:
public:
run() {
std::cout << "THIS SHOULD NOT HAVE BEEN CALLED 1" << std::endl;
}
run(const run&) {
std::cout << "THIS SHOULD NOT HAVE BEEN CALLED 2" << std::endl;
}

template<typename Functor>
run(Functor f) {
std::cout << "CALLED" << std::endl;
f();
}

};

int main() {
run(foo);
run(func());
return 0;

}

My output is:
THIS SHOULD NOT HAVE BEEN CALLED 1

and clearly not what I expected. Any hints?

Thanks

Interesting question. More interestingly, it has nothing to do with
"templatized constructor".

Look at the following example. Do you think it would compile and run?

class X { };
int main()
{
X(helloworld);
}

The above code compiles and runs properly. Why? because

X(helloworld);

is treated as a "declaration" by the compiler. ("anything that can be
treated as a declaration will be treated as a declaration"). Thus

int main()
{
X(helloworld);
}

is same as saying
int main()
{
X helloworld; //define variable of type X. The name of the
variable is "helloworld".
}

Thus, in your 'main' function, when you say

run(foo);

this has nothing to do with the "foo" function that you have defined.
Rather, it defines a local variable foo of type run. Clearly this
calls the no-arg constructor of class foo, which prints "THIS SHOULD
NOT HAVE BEEN CALLED 1".

The second line:
run(func());

is again parsed as a declaration - this time, it is read as

run func();

which declares a function func that takes nothing returns an object of
type run. Since this is merely a declaration, no contructor or
templatized function is executed.

BTW, __FUNC__ is implementation-dependent entity.


-N
 
R

Reetesh Mukul

Interesting question. More interestingly, it has nothing to do with
"templatized constructor".

Look at the following example. Do you think it would compile and run?

class X { };
int main()
{
X(helloworld);

}

The above code compiles and runs properly. Why? because

X(helloworld);

is treated as a "declaration" by the compiler. ("anything that can be
treated as a declaration will be treated as a declaration"). Thus

int main()
{
X(helloworld);

}

is same as saying
int main()
{
X helloworld; //define variable of type X. The name of the
variable is "helloworld".

}

Thus, in your 'main' function, when you say

run(foo);

this has nothing to do with the "foo" function that you have defined.
Rather, it defines a local variable foo of type run. Clearly this
calls the no-arg constructor of class foo, which prints "THIS SHOULD
NOT HAVE BEEN CALLED 1".

The second line:
run(func());

is again parsed as a declaration - this time, it is read as

run func();

which declares a function func that takes nothing returns an object of
type run. Since this is merely a declaration, no contructor or
templatized function is executed.

BTW, __FUNC__ is implementation-dependent entity.

-N

A quick solution can be:-

run((int(*)())(foo));
run(struct func());

Essentially this gives hint about type names.

Regards,
RM
 
W

werasm

Neelesh Bodas wrote:

Look at the following example. Do you think it would compile and run?

class X { };
int main()
{
X(helloworld);
}

The above code compiles and runs properly. Why? because

X(helloworld);

Runs properly, although different to original intention...
is treated as a "declaration" by the compiler. ("anything that can be
treated as a declaration will be treated as a declaration"). Thus
Yes.

int main()
{
X(helloworld);
}

is same as saying

I think you meant "is not the same as saying"
int main()
{
X helloworld; //define variable of type X. The name of the
variable is "helloworld".
}

In the one case its a declaration of a function pointer, in the other
a definition of the variable. But I think that is what you meant, I'm
just clarifying it a bit for the OP.

Regards,

Werner
 
N

Neelesh Bodas

I think you meant "is not the same as saying"

No i didnot.

int the example given by me, I said that
int main() { X(helloworld);}
is semantically equivalent to (aka "same as" )
int main() { X helloworld;}

-N
 
W

werasm

Neelesh said:
the example given by me, I said that
int main() { X(helloworld);}
is semantically equivalent to (aka "same as" )
int main() { X helloworld;}

Ahhh, I learnt something. Your're right. I was thinking
about this case:

struct X
{
int foo();
};
int f1()
{
X helloworld;
helloworld.foo();
return 0;
}

int f2()
{
X helloworld();
helloworld(); //calls the function that returns X and takes void as
param
return 0;
}

Now for a question. Is this considered a definition? I know that it
is
categorized as a declaration.

X helloworld;

W
 
N

Neelesh Bodas

Now for a question. Is this considered a definition?
I know that it ix categorized as a declaration.

X helloworld;

Yes, it is a definition. This statement defines an object of type X.
The fact that the constructor X::X() is invoked indicates that this is
a definition.

-N
 
W

werasm

Yes, it is a definition. This statement defines an object of type X.
The fact that the constructor X::X() is invoked indicates that this is
a definition.

This is exactly why your original wording...

"X(helloworld);

is treated as a "declaration" by the compiler. ("anything that can be
treated as a declaration will be treated as a declaration"). Thus ...
"

confused me.

Yes, its treated as a declaration, but a declaration <is a> definition
in this
case. All said, I've never used the syntax...

X(helloworld)

....before, and confused it with a function ptr returning X named
helloworld (which
is is not, of course).

Kind regards,

Werner
 
J

Joe Greer

See Neelesh Boda's post about what you have actually declared in your main(), but to add
something further. You seem to think that there is a way to invoke a member function on
an object without actually creating an object. There isn't. Why have the run class at
all? Pull your templated function out of the class and invoke it directly. That is:

template <typename Functor>
void run(Functor f)
{
std::cout << "CALLED" << std::endl;
f();
}

int main()
{
run(foo);
run(func());
return 0;
}


Should work as you expect. Generally speaking, if you have a stateless class, think
twice about why you think you want a class. With the exception of functors, namespaces
or classes with static methods work just well (if not better) and you don't have to
create useless instances just to invoke the method.

joe
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,121
Latest member
LowellMcGu
Top