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
#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));