模板参数类型取决于函数参数的模板函数

Template function where template argument type depends on function arguments

我正在将一些 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) 在显式之前从参数推导出类型正如标题所说,模板参数被解析。

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

#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);

Demo

static_assert可以改成SFINAE,但是目前的情况下,我觉得不适应

未来 "concept" 可能会提供其他选择。