Sousuke said:
I'm trying to create a Forwarded template class to do something
similar to perfect forwarding as presented by SG, but without having
to templatize the constructor. The ThreeStrings class should look like
this:
class ThreeStrings
{
public:
ThreeStrings(
Forwarded<std::string> s1,
Forwarded<std::string> s2,
Forwarded<std::string> s3
) : m_s1(s1), m_s2(s2), m_s3(s3)
{
}
private:
std::string m_s1;
std::string m_s2;
std::string m_s3;
};
I've tried several permutations of the following:
template<class T>
class Forwarded
{
private:
typedef decltype(std::forward<T>(*static_cast<T*>(nullptr)))
ForwardedType;
ForwardedType m_forwarded;
public:
template<class T2>
Forwarded(T2&& forwarded) :
m_forwarded(std::forward<T>(forwarded))
{
}
operator ForwardedType() const
{
return std::forward<T>(m_forwarded);
}
};
However, when testing it with a class like ThreeStrings, it always
invokes the std::string copy constructor instead of the move
constructor, even when passing a std::string temporary.
Here's what I get under gcc-4.5.0 (I don't think I've picked up what
compiler you are using - VS2010, since you have nullptr?)
13:30:52 Paul Bibbings@JIJOU
/cygdrive/d/CPPProjects/CLCPP $cat forwarded_test.cpp
// file: forwarded_test.cpp
#include <iostream>
#include <utility>
#define nullptr 0
template<class T>
class Forwarded
{
private:
typedef decltype(std::forward<T>(*static_cast<T*>(nullptr)))
ForwardedType;
ForwardedType m_forwarded;
public:
template<class T2>
Forwarded(T2&& forwarded)
: m_forwarded(std::forward<T>(forwarded))
{ }
operator ForwardedType() const
{ return std::forward<T>(m_forwarded); }
};
struct B
{
explicit B(int)
{ std::cout << "B::B()\n"; }
B(const B&)
{ std::cout << "B::B(const B&)\n"; }
B(B&&)
{ std::cout << "B::B(B&&)\n"; }
};
class ThreeBs
{
public:
ThreeBs(Forwarded<B> b1, Forwarded<B> b2, Forwarded<B> b3)
: m_b1(b1), m_b2(b2), m_b3(b3)
{ }
private:
B m_b1;
B m_b2;
B m_b3;
};
int main()
{
B b1(1), b3(3);
ThreeBs threeBs(b1, B(2), b3);
}
13:30:58 Paul Bibbings@JIJOU
/cygdrive/d/CPPProjects/CLCPP $i686-pc-cygwin-g++-4.5.0 -std=c++0x
-O0 -static -o forwarded_test forwarded_test.cpp
13:31:11 Paul Bibbings@JIJOU
/cygdrive/d/CPPProjects/CLCPP $./forwarded_test
B::B()
B::B()
B::B()
B::B(B&&)
B::B(B&&)
B::B(B&&)
The copy constructor for B isn't used at all, evidently:
13:34:35 Paul Bibbings@JIJOU
/cygdrive/d/CPPProjects/CLCPP $nm --demangle --defined-only
forwarded_test.exe | grep B\(
0040c980 T B::B(B&&)
0040c99c T B::B(int)
Also, a constructor for both the lvalue and rvalue reference arguments
are instantiated and ForwardedType evaluates to B&&.
13:34:54 Paul Bibbings@JIJOU
/cygdrive/d/CPPProjects/CLCPP $nm --demangle --defined-only
forwarded_test.exe | grep Forwarded
// ...
0040c9b8 T ThreeBs::ThreeBs(Forwarded<B>, Forwarded<B>, Forwarded<B>)
0040ca18 T Forwarded<B>::Forwarded<B&>(B&&&)
0040ca30 T Forwarded<B>::Forwarded<B>(B&&)
0040eed0 T Forwarded<B>:
perator B&&() const
This equates to the following (effective) instantiation of B:
template<>
class Forwarded<B>
{
private:
B&& m_forwarded;
public:
template<>
Forwarded<B&>(B& forwarded)
: m_forwarded(std::forward<B>(forwarded))
{ }
template<>
Forwarded<B>(B&& forwarded)
: m_forwarded(std::forward<B>(forwarded))
{ }
operator B&&() const
{
return std::forward<B>(m_forwarded);
}
};
and, what is more, this /probably/ shouldn't work according to the
letter of the Standard, since for the lvalue reference constructor the
the result of std::forward<B>(forwarded) - an lvalue reference -
probably shouldn't bind to the rvalue reference m_forwarded [citation
needed :]
I'm getting a little lost in this, I have to say, but I wonder if your
problem (which appears to be slightly different from my problem here) is
that the type of Forwarded<T>::m_forwarded is dependent on T and is the
same for all objects of type Forwarded<T> for any T - T&&, in the case
of the above code compiled with gcc-4.5.0 - whereas the parameter of the
constructor may be either an lvalue or rvalue reference. I think that
this *fixes* the type of `copy' that is applied - move, in my case; you
say you're getting copy always.