Ответ 1
Конструктор
Начните с конструктора (ваша первая строка):
Как мы знаем (просто уточняя), decltype(std::forward_as_tuple(9))
есть std::tuple<int&&>
.
Также обратите внимание:
std::is_constructible<int&, int&&>::value == false
на всех платформах компилятора. Поэтому, согласно спецификации, которую вы цитируете, что соответствует последнему рабочему проекту С++ 1z, конструкция в вашей первой строке кода не должна участвовать в разрешении перегрузки.
В clang с libС++ он правильно не компилируется в соответствии с этой спецификацией:
http://melpon.org/wandbox/permlink/7cTyS3luVn1XRXGv
С последним gcc он неправильно компилируется в соответствии с этой спецификацией:
http://melpon.org/wandbox/permlink/CSoB1BTNF3emIuvm
И с последним VS-2015 он неправильно компилируется в соответствии с этой спецификацией:
http://webcompiler.cloudapp.net
(эта последняя ссылка не содержит правильный код, вы должны вставить ее).
В вашей ссылке coliru, хотя вы используете clang, clang неявно использует gcc libstdС++ для std:: lib, поэтому ваши результаты согласуются с моими.
Из этого опроса выяснилось, что только libС++ согласуется как со спецификацией, так и с вашими ожиданиями. Но это еще не конец истории.
Последняя рабочая спецификация, которую вы правильно указали, отличается от спецификации С++ 14, которая выглядит так:
template <class... UTypes> constexpr tuple(tuple<UTypes...>&& u);
Требуется:
sizeof...(Types) == sizeof...(Types)
.is_constructible<Ti, Ui&&>::value
true
для всех i.Эффекты: для всех я инициализирует i-й элемент
*this
сstd::forward<Ui>(get<i>(u))
.Примечание. Этот конструктор не должен участвовать в разрешении перегрузки если каждый тип в
UTypes
неявно конвертируется в его соответствующий тип вTypes
.
Это было N4387, которое изменило спецификацию после С++ 14.
В С++ 14 (а также в С++ 11) на клиенте находится клиент, чтобы is_constructible<Ti, Ui&&>::value
был true
для всех i. И если это не так, у вас есть поведение undefined.
Итак, ваша первая строка кода - это поведение undefined в С++ 11 и С++ 14 и плохо сформированное в рабочем проекте С++ 1z. С поведением undefined все может случиться. Таким образом, все libС++, libstdС++ и VS соответствуют требованиям С++ 11 и С++ 14.
Обновить, вдохновленный T.C. ниже:
Обратите внимание, что удаление этого одного конструктора из разрешения перегрузки может позволить выражению использовать другой конструктор, такой как tuple(const tuple<UTypes...>& u)
. Однако этот конструктор также удаляется из разрешения перегрузки с помощью аналогичного предложения Notes.
std::is_constructible<int&, const int&>::value == false
Увы, T.C. возможно, обнаружили дефект в рабочем проекте. Фактическая спецификация говорит:
std::is_constructible<int&, int&>::value == true
поскольку для ссылки используется const
, а не int
.
Похоже, что libstdС++ и VS еще не реализовали спецификацию post-С++ 14, указанную N4387, и которая в значительной степени указывает, что должно указывать ваши комментарии. libС++ много лет реализовывал N4387 и служил доказательством реализации этого предложения.
Назначение
Для этого требуется:
std::is_assignable<int&, const int&>::value == true
и это действительно так в вашем примере. В этой строке кода. Однако я думаю, что можно было бы аргументировать, что вместо этого ему потребуется:
std::is_assignable<int&&, const int&>::value == true
который является ложным. Теперь, если мы сделаем это изменение, ваше назначение будет undefined, поскольку эта часть спецификации находится в предложении Requires. Поэтому, если вы действительно хотите сделать это правильно, вам нужно переместить spec в предложение Remarks с рецептом "не участвует в разрешении перегрузки". И тогда он будет вести себя так, как ваши комментарии показывают, что вы ожидаете этого. Я бы поддержал такое предложение. Но вам придется это сделать, не спрашивайте меня. Но я предлагаю вам помочь в этом, если хотите.