Is-braces-конструктивная черта типа
Как я могу проверить, является ли конкретный тип typename T
конструктивно из аргументов typename ...Args
в порядке T{Args...}
? Я в курсе std::is_constructible< T, Args... >
тип черта от <type_traits>
, но работает с круглыми скобками, а не с фигурными скобками. У меня нет большого опыта в написании черт типа, поэтому я не могу привести первоначальный пример. В качестве упрощения мы можем принять любые разумные утверждения, даже если это приводит к не слишком значительной потере общности.
4 ответа
template<class T, typename... Args>
decltype(void(T{std::declval<Args>()...}), std::true_type())
test(int);
template<class T, typename... Args>
std::false_type
test(...);
template<class T, typename... Args>
struct is_braces_constructible : decltype(test<T, Args...>(0))
{
};
в c ++ 20 вы можете использовать выражения Requires:
template< class T, class... Args >
inline constexpr bool is_brace_constructible_v = requires {T{std::declval<Args()...};};
Мое решение на основе класса SFINAE:
#include <type_traits>
template< typename ...types >
struct identity
{
};
template< typename ...types >
struct void_t
{
using type = void;
};
template< typename type, typename identity, typename = void >
struct is_embraceable
: std::false_type
{
};
template< typename type, typename ...arguments >
struct is_embraceable< type, identity< arguments... >, void_t< decltype(type{std::declval< arguments >()...}) > >
: std::true_type
{
};
template< typename type, typename ...arguments >
constexpr bool is_embraceable_v = is_embraceable< type, identity< arguments... > >::value;
C++ также позволяет инициализировать ссылки в скобках:
struct dummy{};
dummy a;
dummy & b{a};
dummy c{b};
dummy const& d{a};
dummy e{d};
Но is_braces_constructible
из простого ответа возвращается std::false_type
для инициализированных фигурными скобками ссылок с GCC8, но работает, например, с Clang 7. В ORIGINAL-ответе Ориента также не удается скомпилировать ссылочные скобки с GCC8. Его отредактированный ответ даже возвращается std::false_type
в гораздо большем числе случаев как с GCC8, так и с Clang 7.
Вот ответ C++17, который (надеюсь) работает и для всех случаев с GCC8:
#include <type_traits>
#if __GNUC__
template<
typename T,
typename std::enable_if_t<
std::is_lvalue_reference<T>::value
>* = nullptr
>
constexpr void gcc_workaround_braces_initialize_refs(T& t);
template<typename T>
constexpr void gcc_workaround_braces_initialize_refs(T const& t);
template<
typename T,
typename std::enable_if_t<
!std::is_lvalue_reference<T>::value
>* = nullptr
>
constexpr T&& gcc_workaround_braces_initialize_refs(T&& t);
template< typename T, typename Identity, typename = std::void_t<>>
struct is_braces_constructible_impl : std::false_type {};
template< typename T, typename ...Args >
struct is_braces_constructible_impl<
T,
std::tuple< Args... >,
std::void_t< decltype(gcc_workaround_braces_initialize_refs<T>({std::declval< Args >()...}))>
> : std::true_type {};
#else // !__GNUC__
template< typename T, typename Identity, typename = std::void_t<>>
struct is_braces_constructible_impl : std::false_type {};
template< typename T, typename ...Args >
struct is_braces_constructible_impl<
T,
std::tuple< Args... >,
std::void_t< decltype(T{std::declval< Args >()...}) >
> : std::true_type {};
#endif // !__GNUC__
template<class T, typename... Args>
struct is_braces_constructible {
using type = is_braces_constructible_impl< T, std::tuple< Args... > >;
static inline constexpr bool value = type::value;
};