模板参数类型取决于函数参数的模板函数
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)
在显式之前从参数推导出类型正如标题所说,模板参数被解析。
不确定为什么要传递模板参数。你可以这样做:
#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
是一个输出参数。由于无论如何您都准备重构对此函数的所有调用,因此您可能希望将其设为 return 值。
I would like to ensure that h and l are the same type (say T),
很简单:你可以强加它们是相同的模板类型T
,所以如果你用不同类型的值调用函数,你会得到一个编译错误,因为推导有歧义T
.
所以
template <typename U, typename T>
void bound_check (U v, T l, T h)
{ /* ... */ }
I would like to ensure that h and l are the same type (say T), and T to be at least timplicitly convertible to decltype(v).
您可以使用 static_assert()
检查它(参见 Nikos C. 答案)或者您也可以 SFINAE activate/deactivate 函数(例如,以 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 */ }
I made an (arguably more dangerous) assumption that all possible type Ts are signed
使用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
也适用于浮点类型。
if there is some trick to do template bound_check(T& v) where type are deduced from arguments before explicit template arguments are parsed, as the title says.
没有,据我所知。
无论如何,如果可能的话,您可以通过这种方式取消 "I would like to ensure that h and l are the same type" 检查。
If wonder if there's a way that I can call the function as in bound_check<l, h>(v)
从 C++17 开始,您可以对非类型模板参数使用 auto
。
所以,在 C++17 之前,我想答案是 "no"。
从 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 */ }
在 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,但是目前的情况下,我觉得不适应
未来 "concept" 可能会提供其他选择。
我正在将一些 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)
在显式之前从参数推导出类型正如标题所说,模板参数被解析。
不确定为什么要传递模板参数。你可以这样做:
#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
是一个输出参数。由于无论如何您都准备重构对此函数的所有调用,因此您可能希望将其设为 return 值。
I would like to ensure that h and l are the same type (say T),
很简单:你可以强加它们是相同的模板类型T
,所以如果你用不同类型的值调用函数,你会得到一个编译错误,因为推导有歧义T
.
所以
template <typename U, typename T>
void bound_check (U v, T l, T h)
{ /* ... */ }
I would like to ensure that h and l are the same type (say T), and T to be at least timplicitly convertible to decltype(v).
您可以使用 static_assert()
检查它(参见 Nikos C. 答案)或者您也可以 SFINAE activate/deactivate 函数(例如,以 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 */ }
I made an (arguably more dangerous) assumption that all possible type Ts are signed
使用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
也适用于浮点类型。
if there is some trick to do template bound_check(T& v) where type are deduced from arguments before explicit template arguments are parsed, as the title says.
没有,据我所知。
无论如何,如果可能的话,您可以通过这种方式取消 "I would like to ensure that h and l are the same type" 检查。
If wonder if there's a way that I can call the function as in
bound_check<l, h>(v)
从 C++17 开始,您可以对非类型模板参数使用 auto
。
所以,在 C++17 之前,我想答案是 "no"。
从 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 */ }
在 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,但是目前的情况下,我觉得不适应
未来 "concept" 可能会提供其他选择。