w C++ 1z z pojęciami lite, można to zrobić:
template<class T>
requires std::is_base_of<Foo, T>{}()
void foo(T arg) {
}
ramach obecnego (doświadczalnie) realizacji. Co jest całkiem czyste i jasne. Nie może być sposób zrobić coś takiego:
template<derived_from<Foo> T>
void foo(T arg) {
}
ale nie działało to na zewnątrz. na pewno można zrobić:
template<derived_from_foo T>
void foo(T arg){
}
gdzie mamy własny koncept o nazwie derived_from_foo
że stosuje IFF typu pochodzi od foo
. Nie wiem, jak to zrobić, to koncepcje szablonów - pojęcia generowane z parametrów typu szablonu.
W C++ 14, są dwie metody. Po pierwsze, normalne SFINAE:
template<class T,
class=std::enable_if_t<std::is_base_of<Foo, T>{}>
>
void foo(T arg) {
}
tutaj tworzymy szablon, który rozpoznaje typ T
ze swojego argumentu. Następnie próbuje wyprowadzić swój argument typu sekund z pierwszego argumentu.
Drugi argument typu nie ma nazwy (stąd class=
), ponieważ używamy go tylko do testu SFINAE.
Test to enable_if_t<condition>
. enable_if_t<condition>
generuje typ void
, jeśli condition
jest prawdziwy. Jeśli condition
ma wartość false, nie powiedzie się w "bezpośrednim kontekście", generując błąd zastąpienia.
SFINAE to "Błąd podstawienia nie jest błędem" - jeśli typ T
generuje błąd w "bezpośrednim kontekście" sygnatury szablonu funkcji, nie powoduje to błędu podczas kompilacji, ale powoduje szablon funkcji nie jest w tym przypadku uważany za prawidłowe przeciążenie.
"Natychmiastowy kontekst" jest terminem technicznym, ale w zasadzie oznacza to, że błąd musi być "wystarczająco wcześnie", aby można go było złapać. Jeśli wymaga skompilowania ciał funkcji, aby znaleźć błąd, nie jest to "w bezpośrednim kontekście".
To nie jest jedyny sposób. Osobiście lubię ukrywać mój kod SFINAE za błyszczącym szacunkiem. Poniżej używam tag wysyłający do „ukrycia” awarię gdzieś indziej, zamiast uczynić ją aż przodu w podpisie funkcji:
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>{}) {
}
tu utworzyć typ tag
wysyłki, a to umożliwia konwersję do bazy. tag
pozwala nam z wartościami jako wartości i używać bardziej normalnych operacji C++ na nich (zamiast szablonu jak metaprogramowanie <>
s wszędzie).
Następnie podajemy foo
drugi argument typu tag<Base>
, a następnie konstruujemy go za pomocą tag<T>
. Nie uda się skompilować, jeśli T
nie jest typem pochodnym od Base
.
live example.
Zaletą tego rozwiązania jest to, że kod, który sprawia, że nie działa, wydaje się bardziej intuicyjny - tag<Unrelated>
nie można przekonwertować na tag<Base>
. Nie uniemożliwia to jednak rozważenia tej funkcji dla rozdzielczości przeciążenia, co może stanowić problem.
Droga z mniejszą płytą kotła wynosi:
template<class T>
void foo(T t, Base*=(T*)0) {
}
gdzie wykorzystujemy fakt, że wskaźniki mogą być zamienione wtw istnieje związek wyprowadzenie między nimi.
w C++ 11 (i bez constexpr
wsparcia), najpierw napisać pomocnika:
namespace notstd {
template<bool b, class T=void>
using enable_if_t=typename std::enable_if<b,T>::type;
}
następnie:
template<class T,
class=notstd::enable_if_t<std::is_base_of<Foo, T>::value>
>
void foo(T arg) {
}
jeśli nie podoba ci się pomocnika, otrzymujemy to brzydkie dodatkowe:
template<class T,
class=typename std::enable_if<std::is_base_of<Foo, T>::value>::type
>
void foo(T arg) {
}
t on druga technika C++ 14 powyżej może być również przetłumaczona na C++ 11.
Możesz napisać alias, który wykonuje badanie, jeśli chcesz [? Jak mogę ograniczyć klasę szablonu do niektórych rodzajów]
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) {
}
Podobne do (http://stackoverflow.com/ q/16976720/1708801) –
@ShafikYaghmour Pamiętaj, że to nie jest duplikat. Chcę ograniczyć szablon * funkcji *, podczas gdy połączone pytanie odnosi się do szablonu * klasy *. – becko
@ShafikYaghmour Nie zamknąłbyś go, gdyby był to dokładny duplikat, a na drugiej miałeś odpowiedź? – Barry