我正在将一些C代码移植到C ++,并且遇到了具有以下签名的宏。
bound_check(v, l, h)
在实践中,l
和h
是(整数)常量,可用于模板函数。但是,由于C语言中宽大的类型安全性(以及宏的一般缺陷),v
,l
,h
通常没有相同的类型。
我想确保h
和l
是相同的类型(例如T
),并且T
至少可以暂时转换为{{1} }。
我本可以使用decltype(v)
,但是这需要手动编码template <typename T, T l, T h> void bound_check(...)
的类型。我做出了一个(可能更危险的)假设,即所有可能的类型v
都经过签名,并使用T
来避免对template <long long l, long long h>
进行硬编码。
我想知道是否有一种方法可以像v
那样调用该函数,或者换句话说,是否有一些技巧可以做到bound_check<l, h>(v)
,即从显式模板参数之前的参数推导类型就像标题所说的那样被解析。
答案 0 :(得分:1)
我想确保h和l是相同的类型(例如T),
很简单:您可以将它们设置为相同的模板类型T
,因此,如果使用不同类型的值调用该函数,则会产生编译错误,因为存在歧义推论T
。
所以
template <typename U, typename T>
void bound_check (U v, T l, T h)
{ /* ... */ }
我想确保h和l是相同的类型(例如T),并且T至少可以暂时转换为decltype(v)。
您可以使用static_assert()
进行检查(请参见Nikos C.答案),也可以按以下方式SFINAE激活/停用该功能(例如,以C ++ 11的方式)
template <typename U, typename T>
typename std::enable_if<std::is_convertible<T, U>::value>::type bound_check (U & v, T l, T h)
{ /* do something with v, l and h */ }
我做出了一个(可能更为危险的)假设,即所有可能的类型T均已签名
使用SFINAE,您可以添加相应的测试
template <typename U, typename T>
typename std::enable_if<std::is_convertible<T, U>::value
&& std::is_signed<T>::value>::type bound_check (U & v, T l, T h)
{ /* do something with v, l and h */ }
也许您还可以检查T
是整数类型(std::is_integral
):std::is_signed
对于浮点类型也适用。
如果有一些技巧可以做模板bound_check(T&v),如标题所述,在解析显式模板参数之前,先从参数推导类型。
不,据我所知。
无论如何,只要有可能,您就可以松开“我想确保h和l是相同类型”的检查。
如果想知道是否有一种方法可以像
bound_check<l, h>(v)
那样调用该函数
从C ++ 17开始,您可以将auto
用作非类型模板参数。
因此,在C ++ 17之前,我想答案是“否”。
从C ++ 17开始,您可以编写为
template <auto l, auto h, typename U>
std::enable_if_t<std::is_same_v<decltype(l), decltype(h)>
&& std::is_convertible_v<decltype(l), U>
&& std::is_integral_v<decltype(l)>
&& std::is_signed_v<decltype(l)>> bound_check (U & v)
{ /* do something with v, l and h */ }
答案 1 :(得分:0)
不确定为什么要传递模板参数。您可以这样做:
#include <type_traits>
template <typename V, typename LH>
void bounds_check(V& v, LH l, LH h)
{
static_assert(std::is_integral_v<LH>, "'l' and 'h' must be integrals");
static_assert(std::is_convertible_v<LH, V>,
"'l' and 'h' must be implicitly convertible to 'v'");
// ...
}
此外,看起来v
是一个外部参数。由于您已经准备好重构该函数的所有调用,因此您可能希望将其设为返回值。
答案 2 :(得分:0)
在C ++ 17中,您可以这样做
template <auto l, auto h>
void bound_check(decltype(l)& v)
{
static_assert(std::is_same<decltype(l), decltype(h)>::value, "!");
/*...*/
}
然后命名
int v /* = ..*/;
bound_check<0, 10>(v);
static_assert
可以更改为SFINAE,但在当前情况下,我认为它并不适合。
未来的“概念”可能会提供其他选择。