Я ожидал, что этот код будет работать, но он не скомпилируется с GCC. Он компилируется, если вы поднимаете внутренний класс.
#include <algorithm>
template <typename T>
struct Outer
{
struct Inner
{
int x;
};
Inner vec[3];
};
template <typename T>
bool operator <(const typename Outer<T>::Inner& lhs, const typename Outer<T>::Inner& rhs)
{
return lhs.x < rhs.x;
}
int main()
{
Outer<int> out;
Outer<int>::Inner in;
std::lower_bound(out.vec, out.vec + 3, in);
}
GCC 4.4 имеет это, чтобы сказать:
...
bits/stl_algo.h:2442: error: no match for ‘operator<’ in ‘* __middle < __val’
GCC 4.7 печатает намного больше материала, включая вышеперечисленное, заканчивая этим:
...
bits/stl_algobase.h:957:4: note: couldn't deduce template parameter ‘T’
Я готов поверить, что это не совсем правильно сформированный C ++, но почему бы и нет?
Проблема, как вы упомянули, заключается в том, что компилятор не может определить параметр шаблона. T
, Это потому, что имя типа Outer :: Inner является не выводимый контекст контекст для Т.
Когда параметр шаблона используется только в не выводимом контексте, он не учитывается для вывода аргумента шаблона. Подробности в разделе 14.8.2.4 Стандарта C ++ (2003).
Зачем? Если вы специализируете Outer как:
template <>
struct Outer<int>
{
struct Inner
{
double y;
};
Inner vec[3];
};
Компилятор не может сделать вывод, должен ли Outer :: Inner ссылаться на это определение или предыдущее.
Теперь о решениях. Есть несколько возможных решений:
Я опробовал CRTP подход, так как это звучит так круто!
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;
}
Вот еще один обходной путь.
Почему бы вам не использовать пользовательский компаратор?
template <typename T>
struct Comparer
{
bool operator()(const typename Outer<T>::Inner& lhs, const typename Outer<T>::Inner& rhs)
{
return lhs.x < rhs.x;
}
};
int main()
{
Outer<int> out;
Outer<int>::Inner in;
std::lower_bound(out.vec, out.vec + 3, in, Comparer<int>());
}
Надеюсь, что это работает для вас.
Если вы перегружаете конкретный operator<
за int
проблема исчезнет
bool operator<(const typename Outer<int>::Inner& lhs,
const typename Outer<int>::Inner& rhs)
{
return lhs.x < rhs.x;
}
Более простое решение — определение operator<
внутри Inner
:
template<typename T>
struct Outer
{
struct Inner
{
int x;
bool operator<(const Inner& obj) const
{
return x < obj.x;
}
};
Inner vec[3];
};
Кроме того, это просто быстрое решение. И мой ответ не Зачем Компилятор не может найти operator<
во вложенной ситуации в шаблонном режиме.
Ответ Mar0ux довольно хорош. Вы можете найти дополнительную информацию здесь:
Стефан Т. Лававей: Core C ++, 2 н
Вы должны посмотреть всю серию видео — она содержит много полезной информации, но вы можете начать с минуты 34 или около того, чтобы получить ответ на свой вопрос. Стивен упоминает одно основное правило, которое нужно иметь в виду:
::
является кирпичной стеной для вывода аргумента шаблона, то есть аргумента шаблона T
на левой стороне не может быть выведено.