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

时间:2019-08-23 01:36:57

标签: c++ templates function-templates

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

在实践中,lh是(整数)常量,可用于模板函数。但是,由于C语言中宽大的类型安全性(以及宏的一般缺陷),vlh通常没有相同的类型。

我想确保hl是相同的类型(例如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),即从显式模板参数之前的参数推导类型就像标题所说的那样被解析。

3 个答案:

答案 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);

Demo

static_assert可以更改为SFINAE,但在当前情况下,我认为它并不适合。

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