函数模板:将第一个模板参数默认为第二个

function template: default first template argument to second

本文关键字:参数 默认 第二个 第一个 函数模板      更新时间:2023-10-16

如果没有指定函数模板的第一个模板参数,是否可以将其默认为第二个?

这里有一个小例子:

#include <algorithm>
#include <list>
#include <vector>
template <typename ContainerOut, typename ContainerIn>
ContainerOut KeepNegatives(const ContainerIn& xs)
{
    ContainerOut result;
    auto itOut = std::inserter(result, std::end(result));
    auto isNegative = [](auto x){ return x < 0; };
    std::copy_if(std::begin(xs), std::end(xs), itOut, isNegative);
    return result;
}
int main()
{
    typedef std::vector<int> IntVector;
    typedef std::list<int> IntList;
    IntVector intVector = { 1, -2, -3, 4 };
    IntList intList = { 1, -2, -3, 4 };
    auto intVec2 = KeepNegatives<IntVector>(intList);
    auto intList2 = KeepNegatives<IntList>(intVector);
    auto intVec3 = KeepNegatives<IntVector>(intVector);
}

这是有效的,但我想要的是,在未指定ContainerOut的情况下,KeepNegatives(即ContainerOut)的返回值的类型与输入值(即ContainerIn)的类型相同。因此,下面的代码行将进行编译(现在没有)并返回一个IntVector

    auto intVec4 = KeepNegatives(intVector);

您可以简单地为这种特殊情况添加一个重载:

template <typename ContainerIn>
ContainerIn KeepNegatives(const ContainerIn& xs)
{
    return KeepNegatives<ContainerIn, ContainerIn>(xs);
}

然而,这可能会导致intVec3案例中的歧义。这里有一种方法:

#include <algorithm>
#include <list>
#include <vector>
template <typename ContainerOut, typename ContainerIn, 
          typename = std::enable_if_t<!std::is_same<ContainerOut, ContainerIn>::value>>
ContainerOut KeepNegatives(const ContainerIn& xs)
{
    ContainerOut result;
    auto itOut = std::inserter(result, std::end(result));
    auto isNegative = [](auto x){ return x < 0; };
    std::copy_if(std::begin(xs), std::end(xs), itOut, isNegative);
    return result;
}
template <typename ContainerIn>
ContainerIn KeepNegatives(const ContainerIn& xs)
{
    return KeepNegatives<ContainerIn, ContainerIn, void>(xs);
}

int main()
{
    typedef std::vector<int> IntVector;
    typedef std::list<int> IntList;
    IntVector intVector = { 1, -2, -3, 4 };
    IntList intList = { 1, -2, -3, 4 };
    auto intVec2 = KeepNegatives<IntVector>(intList);
    auto intList2 = KeepNegatives<IntList>(intVector);
    auto intVec3 = KeepNegatives<IntVector>(intVector);
    auto intVec4 = KeepNegatives(intVector);
}

实时

例如std::experimental::make_array采用的一种更好的方法是不直接使用ContainerOut作为返回类型;这允许您指定一个标记类型作为默认值(void是一个简单的选择),然后计算返回类型。

template <typename ContainerOut = void, typename ContainerIn,
          typename ret_t = std::conditional_t<std::is_void<ContainerOut>{},
                                              ContainerIn, ContainerOut>>
ret_t KeepNegatives(const ContainerIn& xs){
      // ...
}

您可以将SFINAE与过载组合如下:

template <typename ContainerOut, typename ContainerIn>
std::enable_if_t<!std::is_same<ContainerOut, ContainerIn>::value, ContainerOut>
KeepNegatives(const ContainerIn& xs) {
    ContainerOut result;
    auto itOut = std::inserter(result, std::end(result));
    auto isNegative = [](auto x) { return x < 0; };
    std::copy_if(std::begin(xs), std::end(xs), itOut, isNegative);
    return result;
}
template <typename ContainerIn>
ContainerIn
KeepNegatives(const ContainerIn& xs) {
    ContainerIn result;
    auto itOut = std::inserter(result, std::end(result));
    auto isNegative = [](auto x) { return x < 0; };
    std::copy_if(std::begin(xs), std::end(xs), itOut, isNegative);
    return result;
}

main:中

    auto intVec2 = KeepNegatives<IntVector>(intList);
    auto intList2 = KeepNegatives<IntList>(intVector);
    auto intVec3 = KeepNegatives(intVector);

现场演示

只提供一个简单的过载作为:

template <typename ContainerIn>
ContainerIn KeepNegatives(const ContainerIn& xs) {...}

如果用户明确地提供了与相同的模板参数,那么您将得到对重载函数的不明确调用

auto intVec3 = KeepNegatives<IntVector>(intVector);