将 SFINAE 与std::is_base_of http://en.cppreference.com/w/cpp/types/is_base_of:
template <typename T,
typename = std::enable_if_t<
std::is_base_of<Foo, T>::value
>>
void foo(T arg);
这将仅包括foo
在过载集中如果T
继承自Foo
。请注意,这也包括不明确和无法访问的基础。如果您想要一个仅允许T
继承的spublicly and 明确地 from Foo
,那么你可以改用std::is_convertible http://en.cppreference.com/w/cpp/types/is_convertible:
template <typename T,
typename = std::enable_if_t<
std::is_convertible<T*, Foo*>::value
>>
void foo(T arg);
注意论证的颠倒。
无论您选择哪种形式,为了简洁起见都可以使用别名:
template <typename T>
using enable_if_foo = std::enable_if_t<std::is_base_of<Foo, T>::value>;
template <typename T,
typename = enable_if_foo<T>>
void foo(T arg);
这有效是因为std::enable_if http://en.cppreference.com/w/cpp/types/enable_if有一个名为的嵌套类型type
当且仅当传入的布尔值是true
. So if std::is_base_of<Foo, T>::value
is true
, enable_if_t
被实例化为void
,就好像我们写过:
template <typename T,
typename = void>
void foo(T arg);
But, if T
不继承自Foo
,那么类型特征将评估为false
, and std::enable_if_t<false>
是替代失败 - 没有typename enable_if<false>::type
。您可能认为这是一个编译错误,但是s代换failure is not an e错误(sfinae)。这只是模板推演失败而已。所以效果是这样的foo<T>
在这种情况下,只是从可行的重载候选集合中删除,与任何其他模板推导失败没有什么不同。