Шаблоны Variadic с прямой ссылкой и оператором +=

У меня есть функция, которая должна принимать несколько параметров и после добавления всех параметров в *this, operator+= перегружен и работает по одному параметру. Функция выглядит

template <typename T, typename U>
struct are_equal :
    std::is_same<typename std::decay<T>::type, U>::type
{};

template<typename T>
template<typename... U>
std::enable_if_t<are_equal<U ..., Object<T>>::value>
Object<T>::addd(U &&... u)
{
//  *this += std::forward<U>(u)...;
}

Вероятно, у меня есть две проблемы. 1. Я думаю, что я должен изменить часть своего кода с type_traitsНо мои эксперименты не дают правильного результата. Ошибка со строкой комментариев (где находится operator +=)

C2893 Не удалось специализировать шаблон функции 'enable_if<_Test, _Ty>:: type Object:: addd (U &&...)' C2672 'Object:: addd': не найдено соответствующей перегруженной функции

  1. Проблема со словарем (?) В строке комментария:

    *this += std::forward<U>(u)...;
    

Ошибка:

Синтаксическая ошибка C2143: отсутствует ';' до '...'

Синтаксическая ошибка C2059: "..."

C3520 'u': пакет параметров должен быть расширен в этом контексте

Operator+= отлично работает для одного элемента (я уверен).

2 ответа

Я предполагаю, что вы хотите, чтобы расширение пакета производило что-то вроде этого:

*this += std::forward<U>(u_1),
*this += std::forward<U>(u_2),
// ...
*this += std::forward<U>(u_n);

Причина по которой *this += std::forward<U>(u)...; не работает то, что, грубо говоря, запятые, созданные расширением пакета (но не выражением сгиба, см. ниже), не могут использоваться в качестве операторов.

Классический обходной путь до C++17 - использовать фиктивный массив:

using dummy_array = int[];
dummy_array{(*this += std::forward<U>(u), 0)..., 0};

Обратите внимание, что запятые, создаваемые этим расширением, не используются как операторы (а скорее как разделители инициализаторов элементов), поэтому указанное выше ограничение не применяется.

Первый , 0 в приведенном фрагменте позволяет нам игнорировать возвращаемый тип *this += blah,
Второй , 0 используется для поддержки пустых пакетов параметров (в противном случае была бы попытка создать пустой массив, что недопустимо).

Псевдоним типа необходим, потому что компилятор не позволит вам использовать int[]{blah, blah} непосредственно.

В качестве альтернативы using, вы могли бы использовать что-то вроде

std::enable_if_t<1, int[]>{(std::cout << p, 0)..., 0};

Другой вариант - создать реальный массив вместо временного:

int dummy_array[]{(std::cout << p, 0)..., 0};
(void)dummy_array;

Но мне это не очень нравится.


Если у вас есть C++17, вы должны использовать вместо этого выражения складывания:

((*this += std::forward<U>(u)), ...);

Я думаю, что вы хотите следующее:

template <bool ... Bs> struct bools {};

template <bool ... Bs>
using all_of = std::is_same<bools<true, Bs...>, bools<Bs..., true>>;

template <typename T, typename ... Ts>
using are_equal = all_of<std::is_same<T, Ts>::value...>;

template<typename T>
template<typename... Us>
std::enable_if_t<are_equal<T, std::decay_t<Us>...>::value>
Object<T>::add(Us&&... u)
{
    const int dummy[] = {0, ((*this += std::forward<Us>(u)), 0)...};
    static_cast<void>(dummy);
}
Другие вопросы по тегам