我正在努力如何在C ++中设计执行以下功能的函数:
用伪代码看起来像这样:
do_stuff(a, b, c, ... n) {
b = a;
c = a;
...
n = a;
}
到目前为止,我想出的内容如下:
template <typename... T> void
do_stuff(const T& in, Args & ... args) {
}
我的问题是,如何使用可变参数包,并确保第一个参数永不更改,并且所有参数都属于同一类型?
答案 0 :(得分:1)
您可以通过使用SFINAE限制函数的参数来做到这一点。此实现使用C ++ 17的fold表达式来避免手动编写递归调用:
#include <type_traits>
template <typename T, typename... Args>
std::enable_if_t<std::conjunction_v<std::is_same<T, Args>...> && sizeof...(Args) >= 1>
broadcast(const T& source, Args&... targets)
{
(targets = ... = source);
}
enable_if
强制T
和Args
的每个成员是同一类型,并且至少有一个参数。
Demo on Godbolt,Demo on Wandbox
在C ++ 11中,您可以使用递归调用有效地实现此目的(以编译时间为代价)。
#include <type_traits>
namespace detail
{
template <typename T>
void broadcast_impl(const T&) {}
template <typename T, typename U, typename... Args>
typename std::enable_if<std::is_same<T, U>::value>::type
broadcast_impl(const T& source, U& first, Args&... remaining)
{
first = source;
broadcast_impl<T, Args...>(source, remaining...);
}
}
template <typename T, typename... Args>
void broadcast(const T& source, T& first, Args&... remaining)
{
detail::broadcast_impl<T, T, Args...>(source, first, remaining...);
}
作为奖励,这是一个不含SFINAE的版本,引入了更高级别的指针间接寻址(因为我们无法创建引用的std::initializer_list
)
#include <initializer_list>
template <typename T, typename... Args>
void broadcast(const T& source, T& first, Args&... targets)
{
std::initializer_list<T*> ts = { &first, &targets... };
for (T* ptr : ts)
*ptr = source;
}