user2023370
user2023370

Reputation: 11037

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: 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.

Upvotes: 6

Views: 2828

Answers (6)

user2023370
user2023370

Reputation: 11037

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

Upvotes: 0

Ise Wisteria
Ise Wisteria

Reputation: 11669

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

Upvotes: 1

Tim
Tim

Reputation: 9172

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.

Upvotes: 0

Konrad Rudolph
Konrad Rudolph

Reputation: 545528

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.

Upvotes: 3

RobH
RobH

Reputation: 3338

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.

Upvotes: 2

Mark B
Mark B

Reputation: 96233

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.

Upvotes: 1

Related Questions