Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何将模板参数限制为模板化接口的专用子代?_C++_Templates_Interface_Template Specialization_Typetraits - Fatal编程技术网

C++ 如何将模板参数限制为模板化接口的专用子代?

C++ 如何将模板参数限制为模板化接口的专用子代?,c++,templates,interface,template-specialization,typetraits,C++,Templates,Interface,Template Specialization,Typetraits,假设以下情况: 有一个模板化接口,定义了对不同数据类型的一组操作 该接口由定义实际数据类型操作的各种专用类实现 有一个管理类必须处理2中定义的类的实例 简化的示例代码可能如下所示: #include <iostream> #include <type_traits> template <typename R, typename S> class ICanDoIt { public: virtual void doStuff() = 0

假设以下情况:

  • 有一个模板化接口,定义了对不同数据类型的一组操作
  • 该接口由定义实际数据类型操作的各种专用类实现
  • 有一个管理类必须处理2中定义的类的实例
  • 简化的示例代码可能如下所示:

    #include <iostream>
    #include <type_traits>
    
    template <typename R, typename S>
    class ICanDoIt
    {
        public:
            virtual void doStuff() = 0;
    
        protected:
            ICanDoIt<R, S>(R rA, S sA) : r(rA), s(sA) {};
            R r;
            S s;
    };
    
    class DoesIt : public ICanDoIt<int, double>
    {
            public:
                DoesIt(int iA, double dA) : ICanDoIt(iA, dA) {};
    
                virtual void doStuff()
                    { std::cout << "r * s = " << r * s << " done." << std::endl; }
    };
    
    template <typename T>
    class NeedsSomeoneWhoCanDoIt
    {
        static_assert(std::is_base_of<ICanDoIt<R, S>, T>::value, 
                      "T needs to be able to do it.");
    
        public:
            NeedsSomeoneWhoCanDoIt(const T& doesItA) : doesIt(doesItA) {};
            void getItDone() { doesIt.doStuff(); };
    
        private:
            T doesIt;
    };
    
    
    int main()
    {
        DoesIt doesIt(5, 2.2);
        NeedsSomeoneWhoCanDoIt<DoesIt> needsIt(doesIt);
        needsIt.getItDone();
    }
    
    #包括
    #包括
    模板
    我的职业
    {
    公众:
    虚空doStuff()=0;
    受保护的:
    ICanDoIt(R-rA,S-sA):R(rA),S(sA){};
    R;
    S S;
    };
    课程名称:public-ICanDoIt
    {
    公众:
    DoesIt(int-iA,double-dA):我做(iA,dA){};
    虚空doStuff()
    
    {std::cout您始终可以使
    R
    S
    的实际类型用于实例化
    ICanDoIt
    可供派生类访问,即

    template <typename R, typename S> class ICanDoIt {
    public:
      typedef R R_t;
      typedef S S_t;
    
      virtual void doStuff() = 0;
    };
    

    根据实际代码的外观,如果您定义一个纯粹的抽象基类(即一个实际类型
    icandotbase
    而不是模板),那么设计可能会变得更清晰,您可以从中继承
    ICanDoIt
    中当前模板化的功能,该功能将再次成为
    DoesIt
    的基础


    needsOne可以直接使用多态基类
    ICANDOTBASE
    ,而不需要额外的类型检查。

    您不需要发布模板参数。基于SFINAE的标准方法可以很好地工作

    namespace detail {
        template<class R, class S>
        std::true_type test(ICanDoIt<R, S>*);
        std::false_type test(...);
    }
    
    template<class T>
    using can_do_it = decltype(detail::test((T*)nullptr));
    
    名称空间详细信息{
    模板
    标准:正确的型式试验(ICanDoIt*);
    标准:假_型试验(…);
    }
    模板
    使用can_do_it=decltype(detail::test((T*)nullptr));
    
    @norritt:尽管我觉得你当前的设计很管用,但它仍然感觉像是运行时多态性的一种奇怪的幻想,是概念的一种过度限制的化身。这是因为,除了使用Boost,似乎没有办法在单个容器中管理具有不同模板参数的模板类实例(boost::any)。这是我使用STL解决方案的一部分,只是我自己不太满意,但这是我想到的最好的方法。C风格的运行时类型转换可以解决所有这些问题;)我对此投了反对票,因为如果
    T
    不是
    ICanDoIt
    ,那么您将得到的编译错误是
    在'struct T'
    中没有名为'R\u T'的类型,这是非常没有帮助的。确实让您更清楚地看到静态断言消息。@Barry:是的,T.C.的解决方案肯定没有那么侵入性,而且总体上更好,但我相信一个错误的
    T
    使得构建失败已经很有帮助了(我可能会在这里添加注释)。
    namespace detail {
        template<class R, class S>
        std::true_type test(ICanDoIt<R, S>*);
        std::false_type test(...);
    }
    
    template<class T>
    using can_do_it = decltype(detail::test((T*)nullptr));