对可变参数模板使用const参数

0 c++ templates metaprogramming template-meta-programming variadic-templates

我对以下可变参数有两个疑问:

#include <iostream>

template <typename T>
T Add(const T& arg_a)
{
    return arg_a;
}

template <typename T, typename... Pack>
T Add(const T& arg_a, const Pack&... arg_list)
{
    return arg_a + Add(arg_list...);
}

int main(int argc, const char* argv[])
{

    auto itLocalSum = Add(1, 2, 3, 4, 5);
    std::cout << "Sum of Add: " << itLocalSum << "\n";

    return 0;
}
Run Code Online (Sandbox Code Playgroud)
  1. 为什么使用const引用作为参数?
  2. 当我将浮点数与整数结合使用时,add(2.3, 43, 32.2)它对我来说显示不正确的值。我该如何解决?

Kae*_*Rin 9

回答问题1

由于某些类型的复制成本很高,因此,如果仅执行sumsum而不修改基础对象,则按const引用传递将消除复制对象的成本。

例如,如果按值传递big vector,则将整个vector复制以调用该函数,而传递const引用则要快得多(可能以指针复制的形式实现)。


问题2的答案

您的问题是,当您计算43 + 32.2返回值是时int,将舍弃小数部分。这是因为T在这种情况下,推导为文字类型43,即int。针对您的问题的两种解决方案:

  1. 使用auto您的返回值。(如果您使用的是c ++ 14)
template <typename T>
T Add(const T& arg_a)
{
    return arg_a;
}

template <typename T, typename... Pack>
auto Add(const T& arg_a, const Pack&... arg_list)
{
    return arg_a + Add(arg_list...);
}
Run Code Online (Sandbox Code Playgroud)
  1. 或者,如果您具有c ++ 17,则只需使用折叠表达式
template <typename... Pack>
auto Add(const Pack&... arg_list)
{
    return (... + arg_list);
}
Run Code Online (Sandbox Code Playgroud)
  1. 如果您使用的是c ++ 11,请使用std :: common_type
template <typename T>
T Add(const T& arg_a)
{
    return arg_a;
}

template <typename T, typename... Pack>
typename std::common_type<T, Pack...>::type Add(const T& arg_a, const Pack&... arg_list)
{
    return arg_a + Add(arg_list...);
}
Run Code Online (Sandbox Code Playgroud)

当std::common_type不起作用时(例如,Add('a', 'b', 'c', 'd')),您仍然可以在c ++ 11中编写自己的求和类型推断器:

template <typename SumLeftT, typename ... Args>
struct sum_t_impl;

template <typename SumLeftT>
struct sum_t_impl<SumLeftT> {
    using type = SumLeftT;
};

template <typename SumLeftT, typename FirstT, typename ... Rest>
struct sum_t_impl<SumLeftT, FirstT, Rest...> {
    using type = typename sum_t_impl<decltype(std::declval<SumLeftT>() + std::declval<FirstT>()), Rest...>::type;
};

template <typename T, typename ... TArgs>
using sum_t = typename sum_t_impl<T, TArgs...>::type;
Run Code Online (Sandbox Code Playgroud)

并更换返回值的类型typename std::common_type<T, Pack...>有sum_t<T, Pack...>。

例如,这适用于带有chars 的包,其中char + char -> int。

int main()
{
    auto itLocalSum = Add('a', 'b', 'c', 'd');
    std::cout << typeid(itLocalSum).name() << std::endl;
    std::cout << "Sum of Add: " << itLocalSum << "\n";
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

将输出:int和394。