简体   繁体   中英

Failing the template function lookup

Consider following example.

#include <iostream>
#include <boost/optional.hpp>

template < typename A >
int boo( const boost::optional< A > &a );

template < typename A >
int foo( const A &a )
{
    return boo( a );
}

template < typename A >
int boo( const boost::optional< A > & )
{
    return 3;
}


int main()
{
    std::cout << "foo = " << foo( 3 ) << std::endl;
    std::cout << "boo = " << boo( 3 ) << std::endl;
}

Compiling this using g++ 4.3.0 throws the next compiling errors:

dfg.cpp: In function ‘int main()’:
dfg.cpp:25: error: no matching function for call to ‘boo(int)’
dfg.cpp: In function ‘int foo(const A&) [with A = int]’:
dfg.cpp:24:   instantiated from here
dfg.cpp:12: error: no matching function for call to ‘boo(const int&)’

What should I do differently (if possible with references from the C++ standard)? Why is it happening and how do I fix it?

EDIT

The fix is to create the correct type in foo :

template < typename A >
int foo( const A &a )
{
    const boost::optional< A > optA( a );
    return boo( optA );
}

But the questions still stands: why is it not created automatically?

return boo( a );

Here type of a is int , and there is no function with name boo which accepts argument of type int . Hence you see this error:

dfg.cpp:25: error: no matching function for call to 'boo(int)'

Even if int can be implicitly converted into boost::optional<int> , the compiler cannot deduce the template argument for boost::optional<T> from the calling site. It's one of the non-deduced contexts where you explicitly need to mention the type as,

   return boo<A>(a);

The Standard says in $14.8.2.1,

if a template-parameter is not used in any of the function parameters of a function template, or is used only in a non-deduced context, its corresponding template-argument cannot be deduced from a function call and the template-argument must be explicitly specified .

To fix this, you need to explicitly specify the type when calling boo , ie

return boo<A>( a );

and

std::cout << "boo = " << boo<int>( 3 ) << std::endl;

EDIT: removed my explanation, it was rubbish, Nawaz's explanation is better..

You are assuming that because optional<int> has an implicit constructor from int, the compiler should know that is the type you are trying to create.

Template type deduction does not extend to that.

You could write your own template of boo with the one that takes optional as a generalisation

template< typename A > int boo( const A& a );
template < typename A >
int boo( const boost::optional< A > & )
{
    return 3;
}

template < typename A >
int boo( const A & a )
{
    return boo<A>(boost::optional(a)); // allows implicit conversion
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM