Ошибка в методе, основанном на расширении шаблона, дает ошибку компилятора, когда метод явно вызван. Хотя, когда этот метод отмечен как виртуальный, он создает ошибку компилятора независимо от того, действительно ли он вызван. Есть ли что-нибудь в стандарте C++, объясняющее, почему маркирование этих методов как виртуальных приводит к ошибке компилятора?Наследование с возможной ошибкой шаблона
#include <memory>
#include <iostream>
template <class T_>
class Foo
{
protected:
T_ data;
public:
Foo(const T_& x) : data(x) { }
Foo(T_&& x) : data(std::move(x)) { }
// comment these two lines out and it works fine.
virtual void test(T_& x) = 0;
virtual void test(T_&& x) = 0;
};
template <class T_>
class Bar : public Foo<T_>
{
public:
using Foo<T_>::Foo;
void test(T_& x)
{
std::cout << "test(&)" << std::endl;
x = this->data;
}
void test(T_&& x)
{
std::cout << "test(&&)" << std::endl;
x = std::move(this->data);
}
};
int main()
{
Bar<std::unique_ptr<int>> x(std::unique_ptr<int>(new int(42)));
}
Также актуальным является [temp.inst]/p11 - «Реализация не должна неявно создавать [...] не виртуальную функцию-член [...] шаблона класса, которая не требует инстанцирования. независимо от того, реализует ли реализация неявно экземпляр виртуальной функции-члена шаблона класса, если бы виртуальная функция-член не создавалась иначе ». –
Декларации * * создаются при создании экземпляра класса. Определения * не являются *, по умолчанию ([temp.inst]/p1). Общее правило заключается в том, что «специализация члена неявно создается, когда специализация ссылается в контексте, требующем определения члена» ([temp.inst]/p2). Используется ли * odr-used *, поскольку такой контекст неясен. Несмотря на это, [temp.inst]/p11 дает возможность компилятора создать экземпляр виртуальной функции-члена, которая иначе не была бы создана. –
@ T.C. Да, я просто нашел ту же цитату. Я не мог понять, когда существует требование, но это, по-видимому, нечеткость самого стандарта. – Columbo