В C++ 1Z с понятиями облегченный, вы можете сделать это:
template<class T>
requires std::is_base_of<Foo, T>{}()
void foo(T arg) {
}
под током (экспериментальной) реализации. Это довольно чисто и понятно. Там может быть способ сделать что-то вроде:
template<derived_from<Foo> T>
void foo(T arg) {
}
, но я не работал его. Вы можете определенно сделать:
template<derived_from_foo T>
void foo(T arg){
}
, где у нас есть собственный концепт под названием derived_from_foo
, которая применяется тогда и только тогда тип является производным от foo
. То, что я не знаю, как это сделать, - это концепции шаблонов - концепции, созданные из параметров типа шаблона.
В C++ 14, здесь два метода. Во-первых, нормальный SFINAE:
template<class T,
class=std::enable_if_t<std::is_base_of<Foo, T>{}>
>
void foo(T arg) {
}
здесь мы создаем шаблон, который выводит тип T
из своего аргумента. Затем он пытается вывести свой второй аргумент типа из первого аргумента.
Аргумент второго типа не имеет имени (следовательно, class=
), потому что мы используем его только для теста SFINAE.
Испытание enable_if_t<condition>
. enable_if_t<condition>
генерирует тип void
, если верно condition
. Если condition
является ложным, он не работает в «непосредственном контексте», генерируя сбой замены.
SFINAE - «Ошибка замены» не является ошибкой »- если ваш тип T
генерирует сбой в« непосредственном контексте »сигнатуры шаблона функции, это не генерирует ошибку времени компиляции, а приводит к в этом случае шаблон функции не считается допустимой перегрузкой.
«Непосредственный контекст» является техническим термином здесь, но в основном это означает, что ошибка должна быть «достаточно ранней», чтобы ее можно было поймать. Если это требует компиляции тел функций, чтобы найти ошибку, то это не в «непосредственном контексте».
Теперь это не единственный способ. Мне лично нравится скрывать мой код SFINAE за блеском респектабельности. Ниже, я использую тег диспетчеризацию, чтобы «скрыть» провал где-то еще, вместо того чтобы положить его прямо перед в сигнатуре функции:
template<class T>
struct tag {
using type=T;
constexpr tag(tag const&) = default;
constexpr tag() = default;
template<class U,
class=std::enable_if_t<std::is_base_of<T,U>{}>
>
constexpr tag(tag<U>) {}
};
struct Base{};
struct Derived:Base{};
template<class T>
void foo(T t, tag<Base> = tag<T>{}) {
}
здесь мы создаем тип tag
отправки, и это позволяет преобразовать в базу. tag
позволяет нам использовать типы как значения и использовать для них более обычные операции на C++ (вместо шаблонного метапрограммирования <>
по всему месту).
Затем мы даем foo
второй аргумент типа tag<Base>
, затем строим его с помощью tag<T>
. Это невозможно скомпилировать, если T
не является производным типом от Base
.
live example.
Приятная вещь об этом решении заключается в том, что код, который делает его неработоспособным, кажется более интуитивно понятным - tag<Unrelated>
не может преобразовать в tag<Base>
. Это, однако, не мешает рассмотрению функции для разрешения перегрузки, что может быть проблемой.
Путь с меньшей котельной пластиной:
template<class T>
void foo(T t, Base*=(T*)0) {
}
где мы используем тот факт, что указатели могут быть преобразованы тогда и только тогда существует вывод отношение между ними.
В C++ 11 (и без поддержки constexpr
), мы сначала написать помощника:
namespace notstd {
template<bool b, class T=void>
using enable_if_t=typename std::enable_if<b,T>::type;
}
затем:
template<class T,
class=notstd::enable_if_t<std::is_base_of<Foo, T>::value>
>
void foo(T arg) {
}
, если вам не нравится, помощник, мы получаем этот уродливый дополнительный:
template<class T,
class=typename std::enable_if<std::is_base_of<Foo, T>::value>::type
>
void foo(T arg) {
}
t второй метод C++ 14 выше также можно перевести на C++ 11.
Вы можете написать псевдоним, который делает тест, если вы хотите: [? Как ограничить класс шаблонов для определенных типов]
template<class U>
using base_test=notstd::enable_if_t<std::is_base_of<Base, U>::value>;
template<class T,
class=base_test<T>
>
void foo(T arg) {
}
, связанные с (http://stackoverflow.com/ q/16976720/1708801) –
@ShafikYaghmour Обратите внимание, что это не дубликат. Я хочу ограничить шаблон * function *, в то время как связанный вопрос относится к шаблону * class *. – becko
@ShafikYaghmour Не могли бы вы закрыть его, если бы это был точный дубликат, и у вас был ответ на другой? – Barry