В следующем, структура Y
перегрузки X
функция члена f
, Обе перегрузки являются шаблонными функциями, но принимают разные аргументы (typename
а также int
), чтобы быть явно указано:
struct X
{
template <typename> static bool f() { return true; }
};
struct Y : public X
{
using X::f;
template <int> static bool f() { return false; }
};
int main()
{
std::cout << Y::f <void>() << " " << Y::f <0>() << std::endl;
}
Это печатает 1 0
используя gcc, как и ожидалось. Тем не менее, Clang (3.3) жалуется, что
[...] error: no matching function for call to 'f'
std::cout << Y::f <void>() << " " << Y::f <0>() << std::endl;
^~~~~~~~~~~
[...] note: candidate template ignored: invalid explicitly-specified argument
for 1st template parameter
template <int> static bool f() { return false; }
^
то есть виден только Y
версия я пробовал
using X::template f;
вместо этого, без успеха. То же самое происходит с нестатическими (шаблонными) функциями-членами. Так это ошибка?
Эта загадка была недавно объяснена мне в свете другого ответа.
Из канала IRC #clang:
[01:16:23] <zygoloid> Xeo: this is a weird corner of the language where clang conforms but the rule is silly
[01:16:31] <Xeo> ... really? :(
[01:16:45] <zygoloid> Xeo: when deciding whether a using-declaration is hidden, we're not allowed to look at the template-parameter-list (nor the return type, iirc)
[01:17:04] <zygoloid> so the derived class declaration of operator()(T) suppresses the using-declaration
[01:17:19] <Xeo> because it has the same signature / parameter types?
[01:17:40] <zygoloid> rigth
Обходной путь должен не определять f
в классе, который uses
производная версия. Вместо этого переместите его во вспомогательный вспомогательный класс (который, в данном случае, задает вопрос, какое определение, по вашему мнению, должно выиграть).
Смотрите здесь для моего ранее проблемного случая: Лямбда-функции в качестве базовых классов
А вот как это исправить, используя дополнительный базовый класс:
кредиты Спасибо @Xeo и людям в гостиная за раскопки этого «глупого правила»
Огромное разочарование вызывает то, что такое ограничение существует и не было ослаблено в C ++ 11 (может быть веская причина, но я не могу себе представить, почему). Я чувствую, что это разрушает всю концепцию иерархии классов.
Во всяком случае, вот один обходной путь, который я нашел. Я включил другую функцию g
это нестатично, чтобы проиллюстрировать различия, потому что этот случай — мой главный интерес.
template <typename Y>
struct X
{
template <typename> static bool f() { return true; }
template <typename> bool g() { return true; }
template <int I>
static bool f() { return Y::template _f <I>(); }
template <int I>
bool g()
{
return static_cast <Y&>(*this).template _g <I>();
}
};
class Y : public X <Y>
{
friend class X <Y>;
template <int> static bool _f() { return false; }
template <int> bool _g() { return false; }
};
int main()
{
Y y;
std::cout << Y::f <void>() << " " << Y::f <0>() << std::endl;
std::cout << y. g <void>() << " " << y. g <0>() << std::endl;
}
Так что вся перегрузка происходит в базовом классе X
, который реализует статический полиморфизм, принимая Y
в качестве аргумента шаблона (к счастью, это уже имело место в моем проекте, поэтому я не меняю дизайн).
Настоящий Y
Реализации в частных функциях _f
, _g
, Этот дизайн хорош, когда есть много производных классов, таких как Y
только с одной перегрузкой в каждом и единственным базовым классом X
с множеством других перегрузок. В этом случае массового дублирования кода избегают. Опять же, это так в моем проекте.
X
не нужно знать возвращаемое значение этих функций. К сожалению, он должен знать тип возвращаемого значения: я пробовал, например, auto g() -> decltype(...)
и снова это decltype
работает только в gcc. Включение c ++ 1y пишет только один auto g()
без конечной спецификации типа возврата, что позволяет избежать проблемы с decltype
, Тем не мение, поддержка Clang для «возврата типа возврата для нормальных функций» (N3638) доступен только в текущей версии SVN.
До тех пор auto g()
становится основным (и стандартным), нужно вычислить тип возвращаемого значения Y
методы, которые могут быть болезненными, особенно если есть много Y
s.
Это все еще выглядит как беспорядок, но, по крайней мере, не полный.