Я знаю, что я хочу, чтобы они делали, мне все равно, как они это делают: Интерфейс.
Я знаю, что я хочу, чтобы они делали, мне все равно, как они делают некоторые из это, но у меня есть твердые идеи о том, как они (или, по крайней мере, большинство из них) выполняют другие биты: абстрактный класс.
Я знаю, что я хочу, чтобы они делали, и как большинство из них сделайте это: Конкретный класс с виртуальными членами.
Вы можете иметь другие случаи, такие как, например, абстрактного класса без абстрактных членов (у вас не может быть экземпляра одного, но какая функциональность он предлагает, он предлагает полностью), но они реже и обычно возникают потому, что конкретная иерархия предлагает себя чисто и откровенно для данного проблема.
(Кстати, я бы не подумал о Петре как о человеке, а о каждом пэтере как о человеке, которого, как говорят, называют Питером. код таким образом, но когда вы думаете об этой проблеме, это более уместно, чем обычно).
Позвольте упростить задачу для gcc:
template<class... Ts, int... Ns>
void error(Base<Ts, Ns...> const &... args) {} // #1
template<class... Ts,
std::enable_if_t<
std::conjunction<std::is_class<std::remove_reference_t<Ts>>...>{}, int> = 0>
void error(Ts &&... args) {} #2
int main()
{
const Base<int, 4> b;
error(b); // call #1
}
Следуя (сложным) правилам overload_resolution
, у нас есть оба метода в качестве жизнеспособных функций обе являются шаблонными, поэтому мы используем более специализированный шаблон
Я (как clang) понимаю, что # 1 более специализирован, чем # 2, но не для gcc
Я бы сказал, gcc bug.
Позвольте упростить задачу для clang:
template<class... Ts, int... Ns>
void error(Base<Ts, Ns...> const &... args) {} // #1
template<class... Ts,
std::enable_if_t<
(... && std::is_class<std::remove_reference_t<Ts>>::value), int> = 0>
void error(Ts&&... args) {} // #2
int main()
{
Derived<int, 4, 4> d;
error(d); // call #2
}
ICE всегда ошибка, так что ошибка clang.
Для разрешения # 2 является точным соответствием, тогда как # 1 требует преобразования производного класса в его базу.
gcc соглашается с тем, что # 2 называется.