模板函数,其中模板参数类型取决于函数参数

Template function where template argument type depends on function arguments

本文关键字:参数 函数 类型 取决于      更新时间:2023-10-16

我正在将一些 C 代码移植到C++,我遇到了一个具有以下签名的宏。bound_check(v, l, h)

实际上,lh是(整数(常量,适用于模板函数。但是,由于 C 语言中宽松的类型安全性(以及宏的一般缺点(,vlh通常没有相同的类型。

我想确保hl是同一类型(比如T(,并且T至少可以灵活地转换为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)一样调用函数,或者在另一种意义上,是否有一些技巧可以做template <T l, T h> bound_check(T& v)在解析显式模板参数之前从参数中推断出类型,如标题所说。

我想

确保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 */ }

不确定为什么要传递模板参数。你可以做:

#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是一个输出参数。由于您已经准备好重构对此函数的所有调用,因此您可能希望将其设置为返回值。

在 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,但在目前的情况下,我认为它没有适应。

未来的"概念"可能会提供其他选择。