为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C++
临摹微笑 2019-08-02 03:02:26
只接受某些类型的C+模板在Java中,您可以定义只接受扩展您选择的类型的泛型类,例如:public class ObservableList<T extends List> {   ...}这是使用“扩展”关键字完成的。在C+中是否有一些简单的等价关键字?
查看完整描述

3 回答

?
开满天机

TA贡献1786条经验 获得超13个赞

我建议用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.




查看完整回答
反对 回复 2019-08-03
?
达令说

TA贡献1821条经验 获得超6个赞

这在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和一个beginend返回的成员函数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和类型特征。




查看完整回答
反对 回复 2019-08-03
?
倚天杖

TA贡献1828条经验 获得超3个赞

目前还没有人提到的简单解决办法就是忽略这个问题。如果我试图使用int作为函数模板中需要容器类(如向量或列表)中的模板类型,我将得到一个编译错误。粗糙而简单,但它解决了问题。编译器将尝试使用您指定的类型,如果失败,它将生成编译错误。

唯一的问题是,您得到的错误消息将是棘手的阅读。然而,这是一种非常普遍的做法。标准库中满是函数或类模板,这些模板期望模板类型的某些行为,并且不做任何检查所使用的类型是否有效的操作。

如果您想要更好的错误消息(或者如果您想捕获不会产生编译器错误但仍然没有意义的情况),可以使用Boost的静态断言或Boost概念_CHECK库,这取决于您想要的复杂程度。

使用最新的编译器,您有一个内置的static_assert,可以用来代替。




查看完整回答
反对 回复 2019-08-03
  • 3 回答
  • 0 关注
  • 390 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信