문제

Given the following function templates:

#include <vector>
#include <utility>

struct Base { };
struct Derived : Base { };

// #1
template <typename T1, typename T2>
void f(const T1& a, const T2& b)
{
};

// #2
template <typename T1, typename T2>
void f(const std::vector<std::pair<T1, T2> >& v, Base* p)
{
};

Why is it that the following code always invokes overload #1 instead of overload #2?

int main()
{
    std::vector<std::pair<int, int> > v;
    Derived derived;

    f(100, 200);  // clearly calls overload #1
    f(v, &derived);         // always calls overload #1

    return 0;
}

Given that the second parameter of f is a derived type of Base, I was hoping that the compiler would choose overload #2 as it is a better match than the generic type in overload #1.

Are there any techniques that I could use to rewrite these functions so that the user can write code as displayed in the main function (i.e., leveraging compiler-deduction of argument types)?

도움이 되었습니까?

해결책

You can either do this:

f(v, static_cast<Base*>(&derived));

Or use SFINAE to remove the first function as a selection candidate:

// Install boost library and add these headers:
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits.hpp>

// #1 - change it to look like this (note the keyword void changed positions)
template <typename T1, typename T2>
typename boost::disable_if<
   typename boost::is_convertible<T2, Base*>, void>::type
f(const T1& a, const T2& b)
{
};

// #2 - this one can stay the same
template <typename T1, typename T2>
void f(const std::vector<std::pair<T1, T2> >& v, Base* p)
{
};

다른 팁

Given that the second parameter of f is a derived type of Base

It's convertible to such, but it is a Derived*. The first template function requires no conversions, and the second requires one, therefore it chooses the first.

This chooses the second:

f(v, static_cast<Base*>(&derived));

On a side note, main returns an int.

Beside the obvious topics about Koenig Lookup that is more or less well implemented by compilers (especially older ones are quite problematic), there are a few pitfalls regarding template specialization.

The specialization requires the types to exactly match (not sure how the std defines this, but from my experience [gcc, msvc] a derived class won't be matched). If you add an ugly cast to Base*, it should work like you intend, optionally add another specialization for Derived...

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top