c ++

时间:2018-09-21 09:29:07

标签: c++ templates

我正在努力如何在C ++中设计执行以下功能的函数:

  • 该函数至少需要两个参数(类型由模板参数定义)
  • 实际的参数数量可能有所不同(例如,还应该包含5个参数)
  • 该函数的所有参数都具有相同的类型
  • 该函数的第一个参数为只读
  • 该函数采用第一个参数的值并将其分配给所有其他参数

用伪代码看起来像这样:

do_stuff(a, b, c, ... n) {
  b = a;
  c = a;
  ...
  n = a;
}

到目前为止,我想出的内容如下:

  template <typename... T> void
    do_stuff(const T& in, Args & ... args) {

  }

我的问题是,如何使用可变参数包,并确保第一个参数永不更改,并且所有参数都属于同一类型?

1 个答案:

答案 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强制TArgs的每个成员是同一类型,并且至少有一个参数。

Demo on GodboltDemo 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...);
}

Demo on Godbolt

作为奖励,这是一个不含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;
}

Demo on Godbolt