开发者

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;
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜