模板函数,其中模板参数类型取决于函数参数
Template function where template argument type depends on function arguments
我正在将一些 C 代码移植到C++,我遇到了一个具有以下签名的宏。bound_check(v, l, h)
实际上,l
和h
是(整数(常量,适用于模板函数。但是,由于 C 语言中宽松的类型安全性(以及宏的一般缺点(,v
、l
h
通常没有相同的类型。
我想确保h
和l
是同一类型(比如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,但在目前的情况下,我认为它没有适应。
未来的"概念"可能会提供其他选择。
- 将可变参数函数的参数封装在类实例中
- QML 使用带有参数C++函数
- 使用可变参数函数作为模板参数
- 如何在C++中伪造虚拟可变参数函数模板?
- 为什么可变参数函数不适用于模板
- C++ std::functional 中的可变参数函数模板
- 可变参数函数指针的定义对于VxWorks spyLib来说不清楚
- 使用可变参数函数覆盖具有不同函数签名的虚函数
- 考虑引用和常量的可变参数函数包装器
- 使用可变参数函数将整数和/或整数数组放入单个 int 数组中
- 在可变参数函数中转发特定范围的参数
- 通过引用传递参数;函数返回类型是否必须为 VOID?
- 使用带有一个参数函数的递归找到数字的平方
- 可变参数函数模板不能很好地使用 std::function 作为参数
- 多个可变参数函数的单个模板参数包?
- 参数数据类型未知的可变参数函数
- 可变参数函数参数包扩展
- 使用模板可变参数函数将多个参数传递给另一个函数
- 对可变参数函数的递归调用的链接器错误
- 通过像printf这样的可变参数函数传递一个带有常量字符*转换函数的类