【问题标题】:Is-braces-constructible type trait大括号可构造类型特征
【发布时间】:2014-08-16 23:26:21
【问题描述】:

如何检查特定类型 typename T 是否可以以 T{Args...} 的方式从参数 typename ...Args 构造?我知道来自<type_traits>std::is_constructible< T, Args... > 类型特征,但它适用于括号,而不是花括号。我在编写类型特征方面没有太多经验,所以我无法提供最初的例子。为简化起见,我们可以接受任何合理的断言,即使这不会导致太严重的一般性损失。

【问题讨论】:

  • @chris 但是struct A { std::set< int > a; int b; }; using variant_type = boost::variant< int, double, A >; 变体类型呢? std::initializer_list{std::decltype< std::set< int > >(), int()} 没有意义。
  • std::is_constructable> 如果所有参数都是同一类型....

标签: c++ boost typetraits boost-variant


【解决方案1】:
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))
{
};

【讨论】:

  • 可以用结构/类来表示,而不是用函数返回值类型来表示吗?
  • 你可能不再需要这个了,但答案是肯定的;我利用候选template&lt;class... S&gt; struct Satisfied&lt;S..., decltype(void(E))&gt;: std::true_type 的优先级到默认template&lt;class... S, class=void&gt; struct Satisfied: std::false_type。 (E 应该是你对 {S...} 的表达,例如S0{std::declval&lt;S&gt;()...},你明白了。)稍后你可以专精一些f(...) -&gt; std::enable_if_t&lt;Satisfied&lt;...&gt;::value, ...&gt;f(...) -&gt; std::enable_if_t&lt;!Satisfied&lt;...&gt;::value, ...&gt; 而不会产生歧义(在 SFINAE 之后恰好是一个候选人。)
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 或者有一个完整的概念:template concept braces_constructible = requires { T{std::declval()...}; }; template inline constexpr bool is_braces_constructible_v = braces_constructible;
    【解决方案4】:

    C++ allows to brace-initialize references,也是:

    struct dummy{};
    dummy a;
    dummy & b{a};
    dummy c{b};
    
    dummy const& d{a};
    dummy e{d};
    

    但是 is_braces_constructible 来自 Simple's answer 返回 std::false_type 用于使用 GCC8 进行大括号初始化的引用,但可以使用,例如使用 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-29
      • 2013-03-02
      • 2013-09-16
      • 1970-01-01
      • 1970-01-01
      • 2014-09-01
      • 1970-01-01
      相关资源
      最近更新 更多