The problem as you mentioned is that the compiler couldn't deduce template parameter T
. That is because typename Outer::Inner is a nondeduced context context for T.
When a template parameter is used only in a nondeduced context, it's not taken into consideration for template argument deduction. The details are at section 14.8.2.4 of the C++ Standard (2003).
Why? If you specialize Outer as:
template <>
struct Outer<int>
{
struct Inner
{
double y;
};
Inner vec[3];
};
There is no way for the compiler to deduce if Outer::Inner should reference this definition or the previous one.
Now, onto solutions. There are a couple of possible resolutions:
- Move the operator< inside Inner and make it a friend function.
- Define operator< inside Inner like M M. suggested.
- Suggested by Johannes Schaub - litb: Derive inner from a CRTP base parameterized by inner. Then make the parameter type the CRTP class and cast the parameter reference to the derived inner class, the type of which is given by the template argument you deduce.
I tried out the CRTP approach since it sounds so cool!:
template <typename Inner>
struct Base
{
};
template <typename T>
struct Outer
{
struct Inner : Base<Inner>
{
T x;
};
Inner vec[3];
};
template <typename T>
bool operator< (const Base<T>& lhs, const Base<T>& rhs)
{
return static_cast<const T&>(lhs).x < static_cast<const T&>(rhs).x;
}