-
开满天机
我建议用Boost‘s静态断言与is_base_of在Boost Type特性库中:template<typename T>class ObservableList {
BOOST_STATIC_ASSERT((is_base_of<List, T>::value)); //Yes, the double parentheses are needed, otherwise the comma will be seen as macro argument separator
...};在其他一些更简单的情况下,您可以简单地转发-声明一个全局模板,但只为有效类型定义(显式或部分专门化)它:template<typename T> class my_template; // Declare, but don't define// int is a valid typetemplate<> class my_template<int> {
...};// All pointer types are validtemplate<typename T> class my_template<T*> {
...};// All other types are invalid, and will cause linker error messages.
-
达令说
这在C+中通常是没有道理的,正如这里的其他答案所指出的那样。在C+中,我们倾向于基于“从该类继承”以外的其他约束来定义泛型类型。如果你真的想这么做,在C+11和<type_traits>:#include <type_traits>template<typename T>class observable_list {
static_assert(std::is_base_of<list, T>::value, "T must inherit from list");
// code here..};不过,这打破了人们在C+中所期望的许多概念。最好是用一些技巧,比如定义你自己的特质。例如,也许observable_list希望接受任何具有类型防御的容器。const_iterator和一个begin和end返回的成员函数const_iterator..如果将此限制为从list然后,拥有自己类型的用户不会继承list但是提供这些成员函数,并且类型设置将无法使用observable_list.这个问题有两种解决方案,一种是不限制任何东西,并依赖鸭子类型。这个解决方案的一个大缺点是,它涉及到大量的错误,用户很难去摸索。另一种解决方案是定义特征,以约束为满足接口需求而提供的类型。这个解决方案的最大缺点是涉及额外的写作,这可以被看作是烦人的。然而,积极的一面是,您将能够编写自己的错误消息a la。static_assert.为了完整起见,给出了上述示例的解决方案:#include <type_traits>template<typename...>struct void_ {
using type = void;};template<typename... Args>using Void = typename void_<Args...>::type;template<typename T, typename = void>struct has_const_iterator : std::false_type {};template<typename T>struct has_const_iterator<T, Void<typename T::const_iterator>> : std::true_type {};struct has_begin_end_impl {
template<typename T, typename Begin = decltype(std::declval<const T&>().begin()),
typename End = decltype(std::declval<const T&>().end())>
static std::true_type test(int);
template<typename...>
static std::false_type test(...);};template<typename T>struct has_begin_end : decltype(has_begin_end_impl::test<T>(0)) {};template<typename T>class observable_list {
static_assert(has_const_iterator<T>::value, "Must have a const_iterator typedef");
static_assert(has_begin_end<T>::value, "Must have begin and end member functions");
// code here...};在上面的示例中,有许多概念展示了C+11的特性。对好奇者的一些搜索术语是各种模板、SFINAE、表达式SFINAE和类型特征。
-
倚天杖
目前还没有人提到的简单解决办法就是忽略这个问题。如果我试图使用int作为函数模板中需要容器类(如向量或列表)中的模板类型,我将得到一个编译错误。粗糙而简单,但它解决了问题。编译器将尝试使用您指定的类型,如果失败,它将生成编译错误。唯一的问题是,您得到的错误消息将是棘手的阅读。然而,这是一种非常普遍的做法。标准库中满是函数或类模板,这些模板期望模板类型的某些行为,并且不做任何检查所使用的类型是否有效的操作。如果您想要更好的错误消息(或者如果您想捕获不会产生编译器错误但仍然没有意义的情况),可以使用Boost的静态断言或Boost概念_CHECK库,这取决于您想要的复杂程度。使用最新的编译器,您有一个内置的static_assert,可以用来代替。