Следующее отлично работает в Visual C++ 2015 Update 2. Обратите внимание, что A
нельзя копировать, а A::A
— это explicit
.
#include <iostream>
#include <tuple>
struct A
{
explicit A(int i)
{
std::cout << i << " ";
}
// non-copyable
A(const A&) = delete;
A& operator=(const A&) = delete;
};
template <class... Ts>
struct B
{
std::tuple<Ts...> ts;
B(int i)
: ts((sizeof(Ts), i)...)
{
}
};
int main()
{
B<A, A, A, A> b(42);
}
Цель состоит в том, чтобы передать один и тот же аргумент всем элементам кортежа. Правильно выводит:
42 42 42 42
Однако он не компилируется на g++ 4.9.2. Среди многих сообщений есть перегрузка конструктора tuple
, которую, я думаю, следует вызвать:
In instantiation of ‘B<Ts>::B(int) [with Ts = {A, A, A, A}]’:
33:24: required from here
25:30: error: no matching function for call to
‘std::tuple<A, A, A, A>::tuple(int&, int&, int&, int&)’
: ts((sizeof(Ts), i)...)
[...]
/usr/include/c++/4.9/tuple:406:19: note: template<class ... _UElements, class>
constexpr std::tuple< <template-parameter-1-1> >::tuple(_UElements&& ...)
constexpr tuple(_UElements&&... __elements)
^
/usr/include/c++/4.9/tuple:406:19: note: template argument deduction/substitution failed:
/usr/include/c++/4.9/tuple:402:40: error: no type named ‘type’ in
‘struct std::enable_if<false, void>’
template<typename... _UElements, typename = typename
Сигнатура функции в сообщении неполная, но она относится к этой:
template<typename... _UElements, typename = typename
enable_if<__and_<is_convertible<_UElements,
_Elements>...>::value>::type>
explicit constexpr tuple(_UElements&&... _elements)
: _Inherited(std::forward<_UElements>(__elements)...) { }
Насколько я понимаю, is_convertible
не работает для явного конструктора. g++ 5.1 и clang 3.5 имеют похожие сообщения об ошибках.
Теперь в С++ 14, 20.4.2.1/10 говорится: «Этот конструктор не должен участвовать в разрешении перегрузки, если каждый тип в UTypes
неявно преобразуется в соответствующий тип в Types
». Это создает у меня впечатление, что g++ и clang на самом деле имеют такое право, а Visual C++ слишком либерален.
[изменить: похоже, что C++ 17 снял это ограничение, и Visual C++ 2015 следует ему. Теперь он говорит: «Этот конструктор не должен участвовать в разрешении перегрузки, если [...] is_constructible<Ti, Ui&&>::value
не является true
для всех i
». Похоже, что «неявно конвертируемый» был изменен на «is_constructible
». Однако мне все еще нужно решение C++14.]
Я попытался удалить explicit
из конструктора (я бы предпочел сохранить его). Visual C++ снова компилируется нормально, но и g++, и clang жалуются на удаленный конструктор копирования. Поскольку int
теперь неявно преобразуется в A
, я, кажется, в конечном итоге
explicit constexpr tuple(const Types&...)
который неявно преобразует int
s в группу A
s, а затем пытается их скопировать. На самом деле я не уверен, как я когда-либо смогу использовать другой конструктор.
Как в C++14 заставить tuple
инициализировать свои элементы, передав один и тот же аргумент каждому конструктору, если конструкторы explicit
?
explicit
. - person isanae   schedule 12.04.2016!is_convertible
должна бытьexplicit
дляtuple
. - person Jarod42   schedule 12.04.2016sizeof
возвращаетstd::size_t
, беззнаковый тип, но вы принимаете подписанный типint
в качестве параметра. - person Nowhere Man   schedule 12.04.2016sizeof
просто для получения контекста, в котором допустимо расширение пакета параметров. Его значение не используется. - person isanae   schedule 12.04.2016