我需要一个模板表达式,如果定义了第一个参数,则选择第一个参数类型,否则选择第二个参数类型。
select<int, float>::type // type evaluates to int
select<an_undefined_type, float>::type // type evaluates to float
。并且该解决方案必须与 C++03 和 Boost 1.33.1 一起使用:(
我的目标是接受int
和boost::optional<int>
作为函数模板参数T
,因此我可以执行以下操作:
template<typename T>
void fn(T& t)
{
int x = std::numeric_limits<select<T::value_type, T>::type>::digits;
}
因为boost::optional<int>::value_type
是定义的。
C++11解决方案也值得赞赏。
我看不到通过模板专业化来做到这一点的方法,因为我试图专注于概念而不是类型。基本上,我需要一种与any_integer
概念相匹配的专业化和一个与boost::optional<any_integer>
概念相匹配的专业化。
我想使用 C++11 我可以通过以下方式实现这个特定目标:
std::conditional<std::is_integral<T>::value, T, T::value_type>::value
但我没有C++11,我想要更通用的解决方案。
我认为您无法实现所需的确切符号。但是,我认为您可以使用稍微不同的符号来实现您在语义上所追求的内容。您当前符号的问题
int x = std::numeric_limits<select<T::value_type, T>::type>::digits;
是select<T0, T1>
期望两种类型,即,对存在的类型的要求不在select<T0, T1>
模板上,而是在调用它的函数上。我会改变它的方法是使用
int x = std::numeric_limits<select<typename get_value_type<T>::type, T>::type>::digits;
现在需要做的只是有一个get_value_type<T>
,如果存在,它会生成嵌套类型,如果到达那里,某些类型select<T0, T1>
将被忽略,例如,void
(或自定义标记类型)。get_value_type<T>
模板应该相当简单(我看到了 Dirk Holsopple 的答案,但我无法让它工作):
template <typename T>
struct has_value_type
{
typedef char (&true_type)[1];
typedef char (&false_type)[2];
template <typename D> static true_type test(typename D::value_type*);
template <typename D> static false_type test(...);
enum { value = sizeof(test<T>(0)) == 1 };
};
template <typename T, bool = has_value_type<T>::value >
struct get_value_type
{
typedef T type; // EDIT
};
template <typename T>
struct get_value_type<T, true>
{
typedef typename T::value_type type;
};
显然,您可能希望定义略有不同的类型特征,以便您可以使用类似
int x = std::numeric_limits<typename get_type<T>::type>::digits;
如果有value_type
,这将返回嵌套类型,否则T
类型。