支撑可构造型特征

时间:2014-01-02 14:52:51

标签: c++ boost typetraits boost-variant

如何以typename T的方式检查特定类型typename ...Args是否可以从参数T{Args...}构建?我知道来自std::is_constructible< T, Args... >的{​​{1}}类型特征,但它适用于括号,而不是花括号。我没有太多写类型特征的经验,所以我不能提供初步的例子。作为简化,我们可以接受任何合理的断言,即使这导致不太普遍的失去。

4 个答案:

答案 0 :(得分: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))
{
};

答案 1 :(得分:1)

我的类 - 基于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;

答案 2 :(得分:1)

在 c++20 中你可以使用 Requires 表达式:

template< class T, class ...Args >
inline constexpr bool is_brace_constructible_v = requires {T{std::declval<Args>()...};};

答案 3 :(得分:0)

C++ allows to brace-initialize references也是如此:

struct dummy{};
dummy a;
dummy & b{a};
dummy c{b};

dummy const& d{a};
dummy e{d};

但是Simple's answer中的is_braces_constructible对于使用GCC8进行大括号初始化的引用返回std::false_type,但是可以用使用Clang 7的情况。Orient's ORIGINAL answer也无法使用GCC8编译引用括号。在使用GCC8和Clang 7的更多情况下,His EDITED answer甚至返回std::false_type

这是一个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;
};

Live Code