У меня есть структура X
и функция foo
, которая должна получать ссылки rvalue на X
.
Сначала я начал с одного аргумента, и он был прост (ох... времена попроще):
auto foo(X&& arg) -> void {...};
X x;
foo(x); // compile error [OK]
foo(std::move(x)); // accepted [OK]
foo(X{}); // accepted [OK]
Но затем я хотел расширить и принять переменное количество аргументов X
(все еще только ссылки rvalue).
Но есть проблема.
- Во-первых, у вас не может быть
auto foo(X&&... args)
, что было бы идеально - 2. Теперь вы вынуждены делать
template <class... Args> auto foo(Args&&... args)
, но теперь вы получаете ссылки для пересылки, которые с радостью примут невременные:
template <class... Args>
auto foo(Args&&... args) -> void { ... };
X x1, x2;
foo(x1, x2); // accepted [NOT OK]
foo(std::move(x1), std::move(x2)); // accepted [OK]
foo(X{}, X{}); // accepted [OK]
Почему они использовали этот синтаксис и правила для пересылки ссылок, я с самого начала сбивался с толку. Это одна проблема. Другая проблема с этим синтаксисом заключается в том, что T&&
и X<T>&&
— совершенно разные звери. Но здесь мы сбились с пути.
Я знаю, как решить эту проблему с помощью static_assert
или SFINAE
, но оба эти решения немного усложняют ситуацию, и, по моему скромному мнению, они никогда не должны были понадобиться, если бы язык был разработан правильно для одного раза. И даже не заводи меня насчет std::initializer_list
... мы снова сбились с пути.
Итак, мой вопрос: есть ли простое решение/трюк, которого мне не хватает, потому что Args&&
/args
рассматриваются как ссылки на rvalue?
Пока я заканчивал этот вопрос, я думал, что у меня есть решение.
Добавьте удаленные перегрузки для ссылок lvalue:
template <class... Args>
auto foo(const Args&... args) = delete;
template <class... Args>
auto foo(Args&... args) = delete;
Просто, элегантно, должно работать, давайте проверим:
X x1, x2;
foo(x1, x2); // compile error [OK]
foo(std::move(x1), std::move(x2)); // accepted [OK]
foo(X{}, X{}); // accepted [OK]
Окей, у меня есть!
foo(std::move(x1), x2); // accepted [oh c'mon]
static_assert
или SFINAE). Почему? - person Justin   schedule 04.08.2017foo(std::move(x1), x2)
. Значение r для первого аргумента предотвращает выбор любой из перегрузок только для ссылки, но аргумент шаблона для второго аргумента все еще может быть выведен как ссылка на lvalue. - person Justin   schedule 04.08.2017