У меня есть функция, которая должна принимать несколько параметров и после добавления всех параметров в *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’: не найдена соответствующая перегруженная функция
Проблема со словарем (?) В строке комментария:
*this += std::forward<U>(u)...;
Ошибка:
Синтаксическая ошибка C2143: отсутствует ‘;’ до ‘…’
Синтаксическая ошибка C2059: «…»
C3520 ‘u’: пакет параметров должен быть расширен в этом контексте
Operator+=
отлично работает для одного элемента (я уверен).
Я предполагаю, что вы хотите, чтобы расширение пакета производило что-то вроде этого:
*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;
Но мне это не очень нравится.
((*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);
}