对可变参数模板使用 const 参数
Using const parameter for variadic template
我有两个关于以下可变参数的问题:
#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;
}
- 为什么参数使用const引用?
- 当我将浮点数与
add(2.3, 43, 32.2)
等整数组合使用时,它不会向我显示正确的值。我该如何解决?
1) 只是接收参数,不做copy。 const
只是为了让他们"read-only",他们不能改变。此外,当您使用 const 引用时,您可以将右值参数绑定到左值参数,然后您还可以将文字传递给您的函数,例如。
2) 只要每对解包的第一个参数是整数,就会隐式转换为 int。如果将 43
值更改为 43.0
,它将起作用。此外,对于 C++17,您可以放弃 Add
函数并使用折叠表达式:return (arg_a + ... + arg_list);
.
可能更好的解决方案:
template <typename... Pack>
auto Add(const Pack&... arg_list) {
return (arg_list + ...);
}
问题 1 的答案
因为某些类型的复制成本很高,如果您只是简单地做一个不修改底层对象的求和,通过 const 引用传递可以消除复制对象的成本。
例如,如果你通过值传递一个大的 vector
,整个 vector
将被复制来调用函数,而传递一个 const 引用要快得多(可能实现为指针副本)。
问题 2 的答案
您的问题是,当您计算 43 + 32.2
时,return 的值是 int
,舍弃了小数部分。这是因为T
在此上下文中被推导为字面量43
的类型,即int
。针对您的问题的两种解决方案:
- 使用
auto
作为您的 return 值。 (如果您使用的是 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...);
}
- 或者如果你有 c++ 17,只需使用 fold expressions
template <typename... Pack>
auto Add(const Pack&... arg_list)
{
return (... + arg_list);
}
- 如果您使用的是 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...);
}
当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;
并将 return 值类型 typename std::common_type<T, Pack...>
替换为 sum_t<T, Pack...>
。
例如,这适用于具有 char
的包,其中 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;
}
将输出:int
和 394
。
为什么不会你通过引用传递参数?对于整数没关系,但我也可以 Add(std::string{"QWER"}, std::string{"ASDF"}, std::string{"ZXCV"})
并且复制它们可能会非常昂贵。
你总是 return 左侧类型,无论如何。这意味着如果你有Add(2, 3.5)
,结果必须是int
,它会被转换成这样。
为了避免它,你可以推断出 returned 类型:
template <typename T, typename... Pack>
auto Add(const T& arg_a, const Pack&... arg_list)
{
return arg_a + Add(arg_list...);
}
关于错误的金额...问题是
template <typename T, typename... Pack>
T Add(const T& arg_a, const Pack&... arg_list)
{
return arg_a + Add(arg_list...);
}
return 与第一个参数 (T
) 相同类型的值。
因此,如果 T
是一个整数,您将在以下参数中丢失浮点部分。
万一
Add(2.3, 43, 32.2)
你明白了,在43
之后,32.2
变成了32
。
要解决这个问题...如果你会用C++17,你可以使用模板折叠并简单地写
template <typename ... Ts>
auto Add (Ts const & ... as)
{ return (as + ...); }
如果不能用C++17但可以用C++14,可以模拟模板折叠如下
template <typename ... Ts>
auto Add (Ts const & ... as)
{
using unused = int[];
typename std::common_type<Ts...>::type ret{};
(void)unused { 0, ((void)(ret += as), 0)... };
return ret;
}
观察 std::common_type<Ts...>::type
的使用以获得 returned 类型的变量。
如果你只能使用 C++11(所以没有 auto
没有尾随 return 类型),你必须明确 return 类型
template <typename ... Ts>
typename std::common_type<Ts...>::type Add (Ts const & ... as)
{
// same body as in C++14
}
Why is it used const reference for parameters?
当您打算调用它时:
auto itLocalSum = Add(1, 2, 3, 4, 5);
参数必须是 const&
或者只是值。即
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...);
}
或
template <typename T>
T Add(T arg_a)
{
return arg_a;
}
template <typename T, typename... Pack>
T Add(T arg_a, Pack... arg_list)
{
return arg_a + Add(arg_list...);
}
对于简单类型,两者都可以。如果 T
的复制成本很高,const&
会更有效率。
When I use floating numbers with a combination of integers like add(2.3, 43, 32.2) it doesn't show correct value to me. how can I fix it?
您可以使用 43.0
代替 43
。
当您使用 Add(2.3, 43, 32.2)
时,递归调用 Add(43, 32.2)
return 是一个 int
并将 return 值截断为 75
。
我有两个关于以下可变参数的问题:
#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;
}
- 为什么参数使用const引用?
- 当我将浮点数与
add(2.3, 43, 32.2)
等整数组合使用时,它不会向我显示正确的值。我该如何解决?
1) 只是接收参数,不做copy。 const
只是为了让他们"read-only",他们不能改变。此外,当您使用 const 引用时,您可以将右值参数绑定到左值参数,然后您还可以将文字传递给您的函数,例如。
2) 只要每对解包的第一个参数是整数,就会隐式转换为 int。如果将 43
值更改为 43.0
,它将起作用。此外,对于 C++17,您可以放弃 Add
函数并使用折叠表达式:return (arg_a + ... + arg_list);
.
可能更好的解决方案:
template <typename... Pack>
auto Add(const Pack&... arg_list) {
return (arg_list + ...);
}
问题 1 的答案
因为某些类型的复制成本很高,如果您只是简单地做一个不修改底层对象的求和,通过 const 引用传递可以消除复制对象的成本。
例如,如果你通过值传递一个大的 vector
,整个 vector
将被复制来调用函数,而传递一个 const 引用要快得多(可能实现为指针副本)。
问题 2 的答案
您的问题是,当您计算 43 + 32.2
时,return 的值是 int
,舍弃了小数部分。这是因为T
在此上下文中被推导为字面量43
的类型,即int
。针对您的问题的两种解决方案:
- 使用
auto
作为您的 return 值。 (如果您使用的是 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...);
}
- 或者如果你有 c++ 17,只需使用 fold expressions
template <typename... Pack>
auto Add(const Pack&... arg_list)
{
return (... + arg_list);
}
- 如果您使用的是 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...);
}
当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;
并将 return 值类型 typename std::common_type<T, Pack...>
替换为 sum_t<T, Pack...>
。
例如,这适用于具有 char
的包,其中 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;
}
将输出:int
和 394
。
为什么不会你通过引用传递参数?对于整数没关系,但我也可以
Add(std::string{"QWER"}, std::string{"ASDF"}, std::string{"ZXCV"})
并且复制它们可能会非常昂贵。你总是 return 左侧类型,无论如何。这意味着如果你有
Add(2, 3.5)
,结果必须是int
,它会被转换成这样。
为了避免它,你可以推断出 returned 类型:
template <typename T, typename... Pack>
auto Add(const T& arg_a, const Pack&... arg_list)
{
return arg_a + Add(arg_list...);
}
关于错误的金额...问题是
template <typename T, typename... Pack>
T Add(const T& arg_a, const Pack&... arg_list)
{
return arg_a + Add(arg_list...);
}
return 与第一个参数 (T
) 相同类型的值。
因此,如果 T
是一个整数,您将在以下参数中丢失浮点部分。
万一
Add(2.3, 43, 32.2)
你明白了,在43
之后,32.2
变成了32
。
要解决这个问题...如果你会用C++17,你可以使用模板折叠并简单地写
template <typename ... Ts>
auto Add (Ts const & ... as)
{ return (as + ...); }
如果不能用C++17但可以用C++14,可以模拟模板折叠如下
template <typename ... Ts>
auto Add (Ts const & ... as)
{
using unused = int[];
typename std::common_type<Ts...>::type ret{};
(void)unused { 0, ((void)(ret += as), 0)... };
return ret;
}
观察 std::common_type<Ts...>::type
的使用以获得 returned 类型的变量。
如果你只能使用 C++11(所以没有 auto
没有尾随 return 类型),你必须明确 return 类型
template <typename ... Ts>
typename std::common_type<Ts...>::type Add (Ts const & ... as)
{
// same body as in C++14
}
Why is it used const reference for parameters?
当您打算调用它时:
auto itLocalSum = Add(1, 2, 3, 4, 5);
参数必须是 const&
或者只是值。即
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...);
}
或
template <typename T>
T Add(T arg_a)
{
return arg_a;
}
template <typename T, typename... Pack>
T Add(T arg_a, Pack... arg_list)
{
return arg_a + Add(arg_list...);
}
对于简单类型,两者都可以。如果 T
的复制成本很高,const&
会更有效率。
When I use floating numbers with a combination of integers like add(2.3, 43, 32.2) it doesn't show correct value to me. how can I fix it?
您可以使用 43.0
代替 43
。
当您使用 Add(2.3, 43, 32.2)
时,递归调用 Add(43, 32.2)
return 是一个 int
并将 return 值截断为 75
。