Template argument deduction and conversion operators.

B

BigMan

Here is a piece of code:

#include <memory>
using namespace std;

template< typename SomeType >
void f(auto_ptr_ref< SomeType >)
{
}

int __cdecl main(int,char*[])
{
auto_ptr< int > a;
f( a ); // 1: could not deduce template argument
f< int >( a ); // 2: OK
return 0;
}

My question is if there is a standard way to force the compiler to
compile line 1 as it compiles line 2, i.e. to deduce template arguments
in a way that will allow conversion operators to be called if
necessary.
 
V

Victor Bazarov

Here is a piece of code:

#include <memory>
using namespace std;

template< typename SomeType >
void f(auto_ptr_ref< SomeType >)
{
}

int __cdecl main(int,char*[])
{
auto_ptr< int > a;
f( a ); // 1: could not deduce template argument
f< int >( a ); // 2: OK
return 0;
}

My question is if there is a standard way to force the compiler to
compile line 1 as it compiles line 2, i.e. to deduce template arguments
in a way that will allow conversion operators to be called if
necessary.

No. The rule is that the conversions are not applied when trying to
deduce template arguments. There are several (although quite a few)
context in which the argument is deducible, and none of them involve
conversions, IIRC.

V
 
A

Andrey Tarasevich

Here is a piece of code:

#include <memory>
using namespace std;

template< typename SomeType >
void f(auto_ptr_ref< SomeType >)
{
}

int __cdecl main(int,char*[])
{
auto_ptr< int > a;
f( a ); // 1: could not deduce template argument
f< int >( a ); // 2: OK
return 0;
}

My question is if there is a standard way to force the compiler to
compile line 1 as it compiles line 2, i.e. to deduce template arguments
in a way that will allow conversion operators to be called if
necessary.

Of course not. We can even forget about the rules of template argument
deduction. It is impossible for a more generic reason.

The conversion operator that converts 'auto_ptr<T>' to
'auto_ptr<T>::auto_ptr_ref<U>' is itself a template with its own
independent parameter (note 'U'). This means that the above conversion
is infinitely ambiguous. How do you expect the compiler to treat the
line 1? As

f<int>(a.operator auto_ptr_ref<int>());

? Why not

f<double>(a.operator auto_ptr_ref<double>());

or

f<char>(a.operator auto_ptr_ref<char>());

Note, once again, that the parameter of the conversion operator template
is not related in any way to the parameter of the entire 'auto_ptr<>'
class template, which means that from the compiler's point of view the
first variant (with 'int') is in no way better than any other variant.
(It's like solving an equation with two unknowns. In general case it has
infinite number of solutions and no one is better than the others.)

In order to resolve the ambiguity in one way of another you have to
provide compiler with extra information. On way to do it is to specify
the 'f' template argument explicitly and let the compiler to deduce the
argument for the conversion operator

f<int>(a);

Another way would be to perform explicit type conversion and let the
compiler to deduce 'f's template argument

f((auto_ptr<int>::auto_ptr_ref<int>) a);

The last example is provided for purely illustrational purposes, it will
not work in practice because 'auto_ptr_ref' is not a public member of
'auto_ptr'.
 
B

BigMan

Yes, you are right that in the case with auto_ptr and auto_ptr_ref the
call is ambiguous! And all this is due to the templated conversion
operator.
Now, could you consider my previous question in the case where the
conversion operator is not templated as in the code that follows. My
question was: is it possible to deduce templat­e arguments in a way
that will allow conversion operators to be called i­f necessary?

template< typename SomeType >
class RW;

template< typename SomeType >
class RWRef
{
private:
RWRef( RW< SomeType > const* const ){ }
friend RW< SomeType >;
};

template< typename SomeType >
class RW
{
public:
RW( ) { }

operator RWRef< SomeType >( ) const { return RWRef< SomeType >( this
); }
};

template< typename SomeType >
void f
(
RWRef< SomeType >
)
{
}

int main
(
int,
char*[]
)
{
RW< int > a;
f( a );

return 0;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,734
Messages
2,569,441
Members
44,832
Latest member
GlennSmall

Latest Threads

Top