Является ли std::istream_iterator trivially copy constructible?

#include <iterator>
#include <type_traits>

static_assert(std::is_trivially_copy_constructible_v<std::istream_iterator<int>>);

Почему программа компилируется msvc, но не компилируется gcc/clang? https://godbolt.org/z/TfaeqWcMz

Согласно cppreference, std::istream_iterator<int> должен быть trivially copy constructible.


Ответы (1 шт):

Автор решения: tocic

Действительно, согласно стандарту, std::istream_iterator<int> должен быть trivially copy constructible.

[istream.iterator.cons]/6:

istream_iterator(const istream_iterator& x) = default;

...

Remarks: If is_­trivially_­copy_­constructible_­v<T> is true, then this constructor is trivial.

[meta.type.synop]:

namespace std {
...
template<class T, class... Args> struct is_constructible;
...
template<class T, class... Args> struct is_trivially_constructible;
...
template<class T> struct is_trivially_copy_constructible;
...
template<class T, class... Args>
  inline constexpr bool is_constructible_v = is_constructible<T, Args...>::value;
...
template<class T, class... Args>
  inline constexpr bool is_trivially_constructible_v
    = is_trivially_constructible<T, Args...>::value;
...
template<class T>
  inline constexpr bool is_trivially_copy_constructible_v
    = is_trivially_copy_constructible<T>::value;
...
}

[meta.unary.prop]/tab:meta.unary.prop:

Template Condition Preconditions
... ... ...
template<class T, class... Args>
struct is_­constructible;
For a function type T or for a cv void type T,
is_­constructible_­v<T, Args...>
is false, otherwise see below
T and all types in the template parameter pack Args shall be complete types, cv void, or arrays of unknown bound.
... ... ...
template<class T, class... Args>
struct
is_­trivially_­constructible;
is_­constructible_­v<T, Args...>
is true and the variable definition for is_­constructible, as defined below, is known to call no operation that is not trivial ([basic.types], [special]).
T and all types in the template parameter pack Args shall be complete types, cv void, or arrays of unknown bound.
... ... ...
template<class T>
struct
is_­trivially_­copy_­constructible;
For a referenceable type T, the same result as
is_­trivially_­constructible_­v<T, const T&>
, otherwise false.
T shall be a complete type, cv void, or an array of unknown bound.
... ... ...

[meta.unary.prop]/8:

The predicate condition for a template specialization is_­constructible<T, Args...> shall be satisfied if and only if the following variable definition would be well-formed for some invented variable t:

T t(declval<Args>()...);

...

[basic.types]/9:

Arithmetic types ([basic.fundamental]), enumeration types, pointer types, pointer-to-member types ([basic.compound]), std​::​nullptr_­t, and cv-qualified versions of these types are collectively called scalar types. Scalar types, trivially copyable class types ([class.prop]), arrays of such types, and cv-qualified versions of these types are collectively called trivially copyable types. ...

Однако в реализации gcc копирующий конструктор является user-provided, что делает его нетривиальным для любого типа.

istream_iterator(const istream_iterator& __obj)
: _M_stream(__obj._M_stream), _M_value(__obj._M_value),
  _M_ok(__obj._M_ok)
{ }

[class.copy.ctor]/11:

A copy/move constructor for class X is trivial if it is not user-provided and if:

...

clang и msvc в этом случае соответствуют стандарту. В вашем примере для clang вы не указали флаг -stdlib=libc++, поэтому по умолчанию использовалась стандартная библиотека libstdc++, что и в gcc. Сравните.


Интересно, что разработчик gcc опубликовал LWG-3600, в котором предлагает убрать требование trivially copy constructible для std::istream_iterator из стандарта, т.к. изменение реализации поломает ABI libstdc++. Пока что никаких решений по этому поводу не принято.

→ Ссылка