Template function's priority is different between vs2005 and vs2010 - c++

class Foo
{
friend class SquirrelVM;
public:
Foo() { cout << "Ctor" << endl; }
virtual ~Foo() { cout << "Dtor" << endl; }
Foo(const Foo & o) { cout << "const Ctor" << endl; }
template <typename _ty>
Foo(const _ty & val) { cout << "T const Ref" << endl; }
template <typename _ty>
Foo(_ty & val) { cout << "T Ref" << endl; }
template <typename _ty>
Foo(_ty * val) { cout << "T Ptr" << endl; }
};
Foo CreateFoo()
{
Foo ret;
return ret;
}
int main( int argc, char* argv[] )
{
Foo f = CreateFoo();
return 0;
}
Outputs are different between vs2005 and vs 2010.
Expected outputs are like this..
Ctor
const Ctor
Dtor
Dtor
Above outputs are derived if I build in vs2005.
But, vs2010's output is not same with vs2005's
Ctor
T Ref
Dtor
Dtor
Why template function's priority is higher than normal function in vs2010?
[edit]
If const is ommitted on copy constructor, than expected output(which is same with vs2005) comes out. Is there any side effect if form of copy constructor is not same with recomended form? Recomended form.. I mean... Foo(const Foo&); not Foo(Foo&);

Foo(_ty & val) with _ty being Foo is a better match because it will have parameter type Foo& matching a non-const Foo lvalue, while the other has a const that will make it a bit worse match.
There was some confusion during the made-up process of C++0x and before as to whether templates can be used to copy an object of a class to its own class type. The committee just recently figured they want to stop the confusion about it and allow such a thing. VS2010 seems to reflect that decision.

Related

Calling method on temporary objects

I have a class in which I overloaded method. Depending on lifetime of the object given method will be called.
How can I call fun implementation for temporary objects? I thought that std::move() casts its argument to an rvalue. Could you tell me why the code below does not work as intended?
template <typename T>
void fun(T&& arg) {
arg.callamethod();
}
class TestCall {
private:
public:
void callamethod() && {
std::cout << "R VALUE REF" << std::endl;
}
void callamethod() const & {
std::cout << "CONST L VALUE REF" << std::endl;
}
void callamethod() & {
std::cout << "L VALUE REF" << std::endl;
}
};
int main() {
TestCall arg = TestCall();
const TestCall arg2 = TestCall();
fun(arg);
fun(arg2);
fun(std::move(arg)); // calls callamethod() &
fun(std::move(arg2)); // calls callamethod() const &
}
Change your function fun to the following code and you will see that rvalue qualifier on your method callamethod works as expected.
template <typename T>
void fun(T&& arg) {
std::forward<T>(arg).callamethod();
}
Note that the last call:
fun(std::move(arg2));
resolves to the const lvalue option of callamethod as you do not have a const rvalue qualifier option, if you add one it will go to it.

User-defined constructor overload not being parameter-matched to the overload with the argument's superclass

Following the code-snippet below, I attempt to pass a Boo<int> instance through the Boo<T>::Boo(Foo const &) constructor overload, which I cannot manage to do.
#include <iostream>
struct Foo { };
template <typename T>
struct Boo : public Foo
{
// Boo(Boo<T> const &) = delete; // Leaves (2) without a constructor
Boo() { std::cout << "Beep " << sizeof(T) << std::endl; }
Boo(Foo const &) { std::cout << "Boop " << sizeof(T) << std::endl; }
};
void fun(Foo const &) { }
int main()
{
Boo<int> x; // (1) Output: Beep 4
Boo<int> y(x); // (2) Output:
Boo<double> z(x); // (3) Output: Boop 8
fun(x); // (4) Compiles
return 0;
}
In the code-snippet I tried to write a simplistic scenario which can be copy-pasted to play around with, if need be.
At (1), we generate a Boo<int> instance x, which uses the Boo<T>::Boo() constructor overload.
At (2), we pass instance x to the constructor of instance y, which uses the implicitly defined copy constructor Boo<T>::Boo(Boo<T> const &). Hence, we do not receive an output message.
At (3), we pass instance x to the constructor of instance z, which uses the Boo<T>::Boo(Foo const &) constructor overload.
At (4), we confirm that Boo<int> can be implicitly converted to Foo const & by the compiler and passed into the fun(Foo const &) function.
Question: How can I get (2) to go through the same constructor as (3) does, and why does it not already do that?
If anyone can see what I have missed, I would much appreciate it, were it pointed out to me.
Use a delegating constructor:
template <typename T>
struct Boo : public Foo
{
Boo(Boo<T> const & arg) : Boo(static_cast<Foo const&>(arg)) {};
Boo() { std::cout << "Beep " << sizeof(T) << std::endl; }
Boo(Foo const &) { std::cout << "Boop " << sizeof(T) << std::endl; }
};
The reason this fixes it is that there is no longer an implicit copy constructor, which would have been a better match than casting to Foo const& and using constructor Boo<T>::Boo(Foo const&), and calls it manually.

C++: move / forwarding / rvalue delegation shenanigans [duplicate]

This question already has answers here:
Why do you use std::move when you have && in C++11? [duplicate]
(4 answers)
Closed 7 years ago.
Try running this test program :
#include <iostream>
class A {
public:
A() { std::cout << "empty constructor" << std::endl; }
A(const A &a) { std::cout << "copy constructor" << std::endl; }
A(A &&a) { std::cout << "move constructor" << std::endl; }
~A() { std::cout << "destructor" << std::endl; }
A &operator=(const A &o) { std::cout << "copy assignment" << std::endl; return *this; }
A &operator=(A &&o) { std::cout << "move assignment" << std::endl; return *this; }
};
A outside;
template <typename U>
void bar(U &&a) {
outside = std::forward<U>(a);
}
void foo(A &&a) {
bar(a);
}
int main(int argc, char *argv[]) {
foo(A());
return 0;
}
On my compiler, I think GCC 4.4.1, the output is:
empty constructor
empty constructor
copy assignment // what??
destructor
destructor
In my opinion the third line is strange. Why is outside copying a in bar instead of moving it? In other words,hy does foo use the bar(A &a) instantiation of bar instead of bar(A &&a)?
I should mention that this problem is easily fixable by changing foo to
template <typename U>
void foo(U &&a) {
bar(std::forward<U>(a));
}
whereupon the move assignment operator is used instead.
In my code I have a lot of delegation methods and I'd hate to have to stick them all in a .h file and make templates for them. Is there another way of telling the compiler or making it understand that a is used as an rvalue in foo?
EDIT: A few people pointed out this change:
void foo(U &&a) {
bar(std::move(a));
}
I was too slow to indicate that I want foo to be able to accept both:
int main(int argc, char *argv[]) {
foo(A());
return 0;
}
and
int main(int argc, char *argv[]) {
A a;
foo(a);
return 0;
}
The suggested code will incorrectly steal, in the second case, a's resources in main where it should be used as a reference.
Inside your foo function it should be:
bar(std::move(a)) because the parameter a is at that point an lvalue.

Template function is used instead of typed

I have this code:
#include <iostream>
#include <string>
class Foo {
public:
Foo(){};
template<typename T>
Foo (T&) {
std::cout << "template" << std::endl;
}
Foo(Foo&) {
std::cout << "copy" << std::endl;
}
Foo(const Foo&) {
std::cout << "copy2" << std::endl;
}
};
int main(){
Foo f;
Foo f2 (f);
}
It prints "copy", which is correct.
However if I remove the Foo(Foo&):
class Foo {
public:
Foo(){};
template<typename T>
Foo (T&) {
std::cout << "template" << std::endl;
}
//Foo(Foo&) {
// std::cout << "copy" << std::endl;
//}
Foo(const Foo&) {
std::cout << "copy2" << std::endl;
}
};
int main(){
Foo f;
Foo f2 (f);
}
it prints "template". I expected it to print "copy2" because it is typed parameters. Why is it using template instead?
In order to perform overload resolution, the compiler needs to evaluate the constructor template using template argument deduction. So it creates a constructor like this:
template<>
Foo<Foo>::Foo(Foo&);
This constructor takes an lvalue reference to non-const, as oppose to the non-template constructor. This is preferred because an identity conversion (i.e no conversion) is preferred over a qualification conversion.
Foo f;
f is not a const object of Foo. So its type match to following function and it will print template.
template<typename T>
Foo (T&) {
std::cout << "template" << std::endl;
}
If you define f as follows, it will print as you expected.
const Foo f;
For the same reason that your first code sample doesn't print copy2. The f you are referencing is not const, so the compiler first tries non-const references. Overload matching matches template<typename T=Foo> Foo(T&) giving an exact match while Foo(const Foo&) requires a cv-adjustment of the parameter being passed.
Try the following:
#include <iostream>
class Foo {
public:
Foo(){};
template<typename T>
Foo (T&) {
std::cout << "template" << std::endl;
}
//Foo(Foo&) {
// std::cout << "copy" << std::endl;
//}
Foo(const Foo&) {
std::cout << "copy2" << std::endl;
}
};
int main(){
const Foo f;
Foo f2 (f);
}
http://ideone.com/zOf1qX

template pass by const reference

I've looked over a few similar questions, but I'm still confused. I'm trying to figure out how to explicitly (not by compiler optimization etc) and C++03-compatible avoid copying of an object when passing it to a specialized template function. Here is my test code:
#include <iostream>
using namespace std;
struct C
{
C() { cout << "C()" << endl; }
C(const C&) { cout << "C(C)" << endl; }
~C() { cout << "~C()" << endl; }
};
template<class T> void f(T) { cout << "f<T>" << endl; }
// This shows two possible ways, I don't need two overloads
// If I do it like (2) the function is not called, only if I do it like (1)
template<> void f(C c) { cout << "f<C>" << endl; } // (1)
template<> void f(const C& c) { cout << "f<C&>" << endl; } // (2)
int main()
{
C c;
f(c);
return 0;
}
(1) accepts the object of type C, and makes a copy. Here is the output:
C()
C(C)
f<C>
~C()
~C()
So I've tried to specialize with a const C& parameter (2) to avoid this, but this simply doesn't work (apparently the reason is explained in this question).
Well, I could "pass by pointer", but that's kind of ugly. So is there some trick that would allow to do that somehow nicely?
EDIT: Oh, probably I wasn't clear. I already have a templated function
template<class T> void f(T) {...}
But now I want to specialize this function to accept a const& to another object:
template<> void f(const SpecificObject&) {...}
But it only gets called if I define it as
template<> void f(SpecificObject) {...}
Basically what I want to do with this specialization is to adapt the SpecificObject to the template interface like
template<> void f(SpecificObject obj){ f(obj.Adapted()); } // call the templated version
EDIT2: Ok, I can force the const C& specialization to be called this way:
f<const C&>(c);
but is there a way to make it work like this as just f(c)?
EDIT3: If someone would eventually have similar questions, I finally found this link in another question, and it is helpful: http://www.gotw.ca/publications/mill17.htm
You're conflating three issues: templates, overloading and argument passing.
Just remove the specializations and pass the argument as T const&.
Cheers & hth.,
Why don't you overload:
void f(const C& c) { cout << "f(const C&)" << endl; }
This would work:
int main()
{
C c;
f<const C&>(c);
return 0;
}
Your alternative:
template<typename T> void f(const boost::reference_wrapper<T const>& c)
{ cout << "f<boost_const_ref&>" << endl; }
int main()
{
C c;
f(boost::cref(c));
return 0;
}
In reality you would use boost::reference_wrapper to pass the reference through to where you want to use it. You can use get() to do that, although boost::reference_wrapper has an implicit conversion back to the reference, so you could probably get by without the partial-specialisation of the template and just passing boost::cref(c) to the regular one.
So if you don't always want to accept a const reference (which is reasonable for base types [int, long, float etc.]), you can use a little boost magic.
#include <iostream>
#include <boost/call_traits.hpp>
using namespace std;
struct C
{
C() { cout << "C()" << endl; }
C(const C&) { cout << "C(C)" << endl; }
//C& operator=(C const&) { cout << "C=C" << endl; return *this; }
~C() { cout << "~C()" << endl; }
};
template<class T> void foo(typename boost::call_traits<T>::param_type inst) { cout << "f<T>" << endl; }
// specialization for calling class C
template<> void foo<C>(boost::call_traits<C>::param_type inst) { cout << "f<C>" << endl; }
int main()
{
int i = 0;
foo<int>(i);
C c;
foo<C>(c);
return 0;
}
Your problem is that the actual parameter c isn't const, so the main template is a better match because it doesn't need to add 'const' to the type. If you try functions that pass by value and by non-const reference, the compiler will tell you that it cannot resolve that difference.
#include <iostream>
using namespace std;
struct C
{
C() { cout << "C()" << endl; }
C(const C&) { cout << "C(C)" << endl; }
~C() { cout << "~C()" << endl; }
};
template<class T> void f(const T&) { cout << "f<T>" << endl; }
int main()
{
C c;
f(c);
return 0;
}
This does do what you would like, but you must then use a const ref for all values passed into the function. I do not know if this was what you were looking for.