猿问

请问只接受某些类型的C+模板

只接受某些类型的C+模板

在Java中,您可以定义只接受扩展您选择的类型的泛型类,例如:

public class ObservableList<T extends List> {
  ...}

这是使用“扩展”关键字完成的。

在C+中是否有一些简单的等价关键字?



临摹微笑
浏览 392回答 3
3回答

开满天机

我建议用Boost‘s静态断言与is_base_of在Boost Type特性库中:template<typename&nbsp;T>class&nbsp;ObservableList&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;BOOST_STATIC_ASSERT((is_base_of<List,&nbsp;T>::value));&nbsp;//Yes,&nbsp;the&nbsp;double&nbsp;parentheses&nbsp;are&nbsp;needed,&nbsp;otherwise&nbsp;the&nbsp;comma&nbsp;will&nbsp;be&nbsp;seen&nbsp;as&nbsp;macro&nbsp;argument&nbsp;separator &nbsp;&nbsp;&nbsp;&nbsp;...};在其他一些更简单的情况下,您可以简单地转发-声明一个全局模板,但只为有效类型定义(显式或部分专门化)它:template<typename&nbsp;T>&nbsp;class&nbsp;my_template;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Declare,&nbsp;but&nbsp;don't&nbsp;define//&nbsp;int&nbsp;is&nbsp;a&nbsp;valid&nbsp;typetemplate<>&nbsp;class&nbsp;my_template<int>&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;...};//&nbsp;All&nbsp;pointer&nbsp;types&nbsp;are&nbsp;validtemplate<typename&nbsp;T>&nbsp;class&nbsp;my_template<T*>&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;...};//&nbsp;All&nbsp;other&nbsp;types&nbsp;are&nbsp;invalid,&nbsp;and&nbsp;will&nbsp;cause&nbsp;linker&nbsp;error&nbsp;messages.

达令说

这在C+中通常是没有道理的,正如这里的其他答案所指出的那样。在C+中,我们倾向于基于“从该类继承”以外的其他约束来定义泛型类型。如果你真的想这么做,在C+11和<type_traits>:#include&nbsp;<type_traits>template<typename&nbsp;T>class&nbsp;observable_list&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;static_assert(std::is_base_of<list,&nbsp;T>::value,&nbsp;"T&nbsp;must&nbsp;inherit&nbsp;from&nbsp;list"); &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;code&nbsp;here..};不过,这打破了人们在C+中所期望的许多概念。最好是用一些技巧,比如定义你自己的特质。例如,也许observable_list希望接受任何具有类型防御的容器。const_iterator和一个begin和end返回的成员函数const_iterator..如果将此限制为从list然后,拥有自己类型的用户不会继承list但是提供这些成员函数,并且类型设置将无法使用observable_list.这个问题有两种解决方案,一种是不限制任何东西,并依赖鸭子类型。这个解决方案的一个大缺点是,它涉及到大量的错误,用户很难去摸索。另一种解决方案是定义特征,以约束为满足接口需求而提供的类型。这个解决方案的最大缺点是涉及额外的写作,这可以被看作是烦人的。然而,积极的一面是,您将能够编写自己的错误消息a la。static_assert.为了完整起见,给出了上述示例的解决方案:#include&nbsp;<type_traits>template<typename...>struct&nbsp;void_&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;using&nbsp;type&nbsp;=&nbsp;void;};template<typename...&nbsp;Args>using&nbsp;Void&nbsp;=&nbsp;typename&nbsp;void_<Args...>::type;template<typename&nbsp;T,&nbsp;typename&nbsp;=&nbsp;void>struct&nbsp;has_const_iterator&nbsp;:&nbsp;std::false_type&nbsp;{};template<typename&nbsp;T>struct&nbsp;has_const_iterator<T,&nbsp;Void<typename&nbsp;T::const_iterator>>&nbsp;:&nbsp;std::true_type&nbsp;{};struct&nbsp;has_begin_end_impl&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;template<typename&nbsp;T,&nbsp;typename&nbsp;Begin&nbsp;=&nbsp;decltype(std::declval<const&nbsp;T&>().begin()), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;typename&nbsp;End&nbsp;&nbsp;&nbsp;=&nbsp;decltype(std::declval<const&nbsp;T&>().end())> &nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;std::true_type&nbsp;test(int); &nbsp;&nbsp;&nbsp;&nbsp;template<typename...> &nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;std::false_type&nbsp;test(...);};template<typename&nbsp;T>struct&nbsp;has_begin_end&nbsp;:&nbsp;decltype(has_begin_end_impl::test<T>(0))&nbsp;{};template<typename&nbsp;T>class&nbsp;observable_list&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;static_assert(has_const_iterator<T>::value,&nbsp;"Must&nbsp;have&nbsp;a&nbsp;const_iterator&nbsp;typedef"); &nbsp;&nbsp;&nbsp;&nbsp;static_assert(has_begin_end<T>::value,&nbsp;"Must&nbsp;have&nbsp;begin&nbsp;and&nbsp;end&nbsp;member&nbsp;functions"); &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;code&nbsp;here...};在上面的示例中,有许多概念展示了C+11的特性。对好奇者的一些搜索术语是各种模板、SFINAE、表达式SFINAE和类型特征。

倚天杖

目前还没有人提到的简单解决办法就是忽略这个问题。如果我试图使用int作为函数模板中需要容器类(如向量或列表)中的模板类型,我将得到一个编译错误。粗糙而简单,但它解决了问题。编译器将尝试使用您指定的类型,如果失败,它将生成编译错误。唯一的问题是,您得到的错误消息将是棘手的阅读。然而,这是一种非常普遍的做法。标准库中满是函数或类模板,这些模板期望模板类型的某些行为,并且不做任何检查所使用的类型是否有效的操作。如果您想要更好的错误消息(或者如果您想捕获不会产生编译器错误但仍然没有意义的情况),可以使用Boost的静态断言或Boost概念_CHECK库,这取决于您想要的复杂程度。使用最新的编译器,您有一个内置的static_assert,可以用来代替。
随时随地看视频慕课网APP
我要回答