使用模板的部分特化我想创建一个函数/方法:
A)只处理形式参数的一个特定基本类型(int,double,float,...)和其他类型抛出异常
template <class T>
T min ( Point <T> p )
{
/*if (T == int) continue;
else throw exception*/
}
B)处理形式参数的更多非原始类型(用户定义类型)以及抛出异常的其他类型......
一些代码示例会有所帮助(没有c ++ boost库)。谢谢你的帮助。
答案 0 :(得分:7)
这是您的问题的解决方案(A部分)。
template<bool b> struct compile_time_assert;
template<>
struct compile_time_assert<true>
{};
template<class T>
struct is_int
{
static const bool value = false;
};
template<>
struct is_int<int>
{
static const bool value = true;
};
template <class T>
T min ( Point <T> p )
{
/*
since you can check error at compile time, there is no reason to
raise exception (which is at runtime) if T is not int!
the following assert will not compile if T is not int.
not only that, you can even see the error message "_error_T_is_not_int"
if T is not int;
*/
compile_time_assert<is_int<T>::value> _error_T_is_not_int;
//your code
}
请参阅以下示例代码。
同样,您可以为其他类型编写模板,(double,char,等等)。或者,更好的是,您只需将所有这些合并到一个struct
中,而是可以在单个模板中定义多个布尔值(针对每种类型),例如static const bool is_T_int = true;
。等等做实验,你会学到的!
但是,我想知道你是否希望你的函数只处理一种类型,那么为什么要定义模板呢?
对于(B)部分,您可以从上面得到这个想法。对?做实验!
答案 1 :(得分:1)
你可以在这里使用boost :: mpl作为B部分,但这是使用boost:(
#include <boost/mpl/at.hpp>
#include <boost/mpl/map.hpp>
#include <boost/mpl/bool.hpp>
using namespace boost;
typedef mpl::map<
mpl::pair<int, mpl::true_>,
mpl::pair<double, mpl::false_>,
mpl::pair<float, mpl::false_>
> TAllowedTypesForMin;
template <class T>
T min (T p)
{
const bool allowed = mpl::at<TAllowedTypesForMin, T>::type::value;
if (allowed)
{
}
return p;
}
修改强>
使用编译时检查一切都更简单:
#include <boost/mpl/set.hpp>
#include <boost/mpl/assert.hpp>
using namespace boost;
template<class T> struct Point {};
typedef mpl::set<int, double, float> TAllowedTypesForMin;
template <class T>
T min (Point<T> p)
{
typedef mpl::has_key<TAllowedTypesForMin, T> allowedType;
BOOST_MPL_ASSERT_MSG( allowedType::value, NOT_SUPPORTED_TYPE, () );
// do something
return T();
}
int main()
{
min(Point<long>());
return 0;
}
答案 2 :(得分:1)
正如Alexender C.的评论中提到的,你确定编译错误不太适合吗?
template <typename T> struct GateKeeper;
// Func we want to call
template <typename S, typename T> void foo (T t);
// Warpper that checks the type and forwards the call
template <typename T> inline void foo (T t)
{
//
// This call will fail for unless a specialization of
// GateKeeper for `T` is defined with a member TYPE
foo< typename GateKeeper<T>::TYPE, T > ( t );
}
//
// This declaration "allows" the type int.
template <> struct GateKeeper<int> { typedef int TYPE; };
void bar ()
{
foo (0); // Compiles
foo (0.0); // Causes error in wrapping foo
}
部分特化可用于允许给定模板的任何特化:
// Some template type
template <typename T>
class TmplType
{
};
// This allows for specializations of TmplType
template <typename T> struct GateKeeper< TmplType<T> > { typedef int TYPE; };
void bar ()
{
TmplType<char> tt;
foo (tt); // Compiles
}
对于您希望支持的每种类型,请添加新的专业化。
更新:发生了什么:
注意:我已经从原始版本更改了模板参数名称,以使事情更清晰。
当编译器看到对foo(x)
的调用时,它可以正确专门化的唯一函数是foo<T>(T)
。这是因为它无法推导出foo<S,T>(T)
的所有模板参数。
foo<T>(T)
的正文将调用转发给真正的函数:
foo< typename GateKeeper<T>::TYPE, T > ( t );
(ASIDE:有关何时使用 typename 的说明,请参阅here)
这是一次做两件事。
第一个是提供调用另一个函数所需的2个模板参数(S和T)。
第二种是使用GateKeeper<T>
的成员作为另一种类型。类型GateKeeper<T>
必须完整并具有该成员。正是这个检查允许我们指定我们想要允许的类型和不允许的类型:
template <typename T> struct GateKeeper; // Incomplete
template <> struct GateKeeper<int> { typedef int TYPE; }; // Complete
由于我们仅为GateKeeper<int>
而非GateKeeper<double>
提供了定义,因此对foo(0)
的调用正常,foo(0.0)
因编译错误而失败。
要允许double
,我们只需要为它添加一个明确的专业化:
template <> struct GateKeeper<double> { typedef int TYPE; }; // double now works.