Implicit conversion to a C++ template object
I have a class A:
template <typename T, int I> struct A {};
and a class B. I would like object's of type B to implicitly convert to A when given as function arguments. B looks like this:
template <typename T>
struct B {
operator A<T,0> &() const { return *new A<T,0>(); }
};
However, my test (below) fails with GCC 4.5, giving the error: 开发者_JAVA技巧no matching function for call to 'test(B&)' Where am I going wrong here? Do other compilers also reject this?
template <typename T, int I>
void test(A<T,I> &a) { delete &a; }
int main(int argc, char *argv[])
{
B<int> b;
test(b);
return 0;
}
p.s. I've now put my own solution in an answer below.
Unrelated to your problem but return *new A<T,0>();
is wrong since it leaks memoryinvites a memory leak. You should not use new
here. return A<T, 0>();
and removing the reference from the return type works just fine and does not leak memory.
If you want an implicit conversion from B to A you would need either:
A cast operator on B:
operator A<T,0>();
or an A constructor which takes a B reference:
A( const B& other );
or for B to derive from A. What you have declared:
operator A<T,0> &() const;
looks a bit like an ill-declared address-of overload.
However, since test() takes a reference (and non-const at that), the casting operator option won't work.
This is what I've tested:
template <typename T, int I> struct A {};
template <typename T>
struct B {
//operator A<T,0> &() const { return *new A<T,0>(); }
template< int I >
operator A<T, I> () const { return A< T, 0 >(); }
};
template <typename T, int I>
void test(A<T,I> &) { }
int f()
{
B<int> b;
A<int, 0> a( b );
test(a); // <-- Success
test(b); // <-- Failure, "could not deduce template argument"
return 0;
}
Conversion to A by initialising a local variable works fine.
Are you sure you actually want such an implicit conversion here? It sounds like a perfect way to confuse yourself or another maintainer, or worse, call a function using the wrong argument because the implicit conversion allows it. Instead, consider a make_A
template like std::make_pair
to explicitly show your intention at the call site.
Providing an overload of test
like the following will enable to write
test(b)
as in the question.
For example:
template <typename T>
void test(B<T> const &b) {
test( static_cast< A<T,0>& >( b ) );
}
test(b); // caller
If such overload isn't allowed but you are allowed to modify B
's
definition, how about providing member function which returns A
like the following, instead of conversion function?
template <typename T>
struct B {
A<T,0> &to_A() const { return *new A<T,0>(); }
};
test( b.to_A() );
If you aren't allowed to modify B
's definition, the above to_A
will be
a free function like the following instead of member function:
template <typename T>
A<T,0> &to_A(B<T> const &b) {
return static_cast< A<T,0>& >( b );
}
test( to_A( b ) );
Hope this helps
This fails in VC++ too. To make it work, add this method:
template <typename T>
void test(B<T> &b)
{
test( static_cast< A<T,0>& > (b) );
}
This will take an actual B
, explicitly do the conversion (via static_cast
), and then call test
using the A
we just made.
I get errors when I run it though. I hope this is just example code, and you're not doing delete &a
in your actual code. RobH gave a better conversion operator for you, and avoids the pointer messiness.
I've settled on using the pass by value conversion operator suggested by Konrad; the explicit template function call of Let_Me_Be; and I sprinkled a little bit of C++0x magic on top: an rvalue reference on the parameter to test. (Or, should that be C++ 2011 now?)
template <typename T, int I> struct A { int x; };
template <typename T>
struct B {
operator A<T,0> () const { return A<T,0>(); }
};
template <typename T, int I>
void test(A<T,I> &&a) { a.x=7; printf("%d\n", x); }
int main(int argc, char *argv[])
{
B<int> b;
test<int,0>(b);
return 0;
}
精彩评论