首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用参数pack参数初始化` `std::array`‘

用参数pack参数初始化` `std::array`‘
EN

Stack Overflow用户
提问于 2019-01-31 10:27:24
回答 3查看 821关注 0票数 0

有带有模板参数的结构HasArray、typename、T和size_t N

代码语言:javascript
复制
template<typename T, size_t N>
struct HasArray {
  // enable_if sizeof...(T) equals N
  template<typename ... Types, typename std::enable_if<sizeof...(Types) == N, int>::type = 0>
  explicit HasArray(Types ... s) : arr { s... } {}
 protected:
  std::array<T, N> arr;
};

我想用构造函数的参数包参数初始化成员数组arr

代码语言:javascript
复制
HasArray<uint32_t, 2> foo(7, 13);

但这会在Clang中产生c++11-narrowing警告。

代码语言:javascript
复制
error: non-constant-expression cannot be narrowed from type 'int' to 'std::__1::array<unsigned int, 2>::value_type' (aka 'unsigned int') in initializer list [-Wc++11-narrowing]

我看不出有什么办法把sTypes型转换成T型,有吗?

编辑感谢您的所有回答。最后,我在打包参数上使用了static_cast<>,在不可转换的情况下使用了SFINAE:

代码语言:javascript
复制
template<typename T, size_t N>
struct HasArray {
  // Use `static_cast` to construct `arr` with `s`
  // Add `enable_if` all `Types` are `is_convertible`
  template<typename ... Types, 
    typename std::enable_if<sizeof...(Types) == N, int>::type = 0,
    typename std::enable_if<(std::is_convertible<Types, T>::value && ...), int>::type = 0>
  explicit HasArray(Types ... s) : arr { static_cast<T>(s)... } {}
 protected:
  std::array<T, N> arr;
};
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-01-31 11:02:17

如果您想要从任何可转换为T的值构造static_cast<T>(...),那么最简单的解决方案就是在构造函数中添加static_cast<T>(...)

代码语言:javascript
复制
template<typename T, size_t N>
struct HasArray {
  template<typename ... Types,
           typename std::enable_if<sizeof...(Types) == N, int>::type = 0>
  explicit HasArray(Types ... s) : arr {static_cast<T>(s)... } {}
protected:
  std::array<T, N> arr;
};

https://godbolt.org/z/TEoZOG

在这种转换不可能的情况下,也可以使用"SFINAE out“构造函数,但在我看来,在当前简单的情况下,默认的错误消息会更好,并且可以在构造函数体中添加更好的消息。

票数 4
EN

Stack Overflow用户

发布于 2019-01-31 10:33:15

您可以使用中级课程:

代码语言:javascript
复制
template <std::size_t, typename T>
using always_t = T;

template <typename T, typename Seq>
struct HasArrayImpl;

template <typename T, std::size_t...Is>
struct HasArrayImpl<T, std::index_sequence<Is...>>
{
    explicit HasArrayImpl(always_t<Is, T> ... v) : arr { v... } {}
protected:
    std::array<T, sizeof...(Is)> arr;
};

template <typename T, std::size_t N>
using HasArray = HasArrayImpl<T, std::make_index_sequence<N>>;

否则,可以将SFINAE扩展到可转换类型和显式转换值。

代码语言:javascript
复制
template<typename T, size_t N>
struct HasArray {
    // enable_if sizeof...(T) equals N
    template <typename ... Types,
             std::enable_if_t<(sizeof...(Types) == N)
                                   && (std::is_convertible<Types, T>::value && ...),
                              int>::type = 0>
    explicit HasArray(Types ... s) : arr{ static_cast<T>(s)... } {}
 protected:
    std::array<T, N> arr;
};
票数 2
EN

Stack Overflow用户

发布于 2019-01-31 11:00:17

我看不出有办法强制要求所有类型都必须是T类型,有吗?

我不明白,从您的问题中,如果您希望Types是可还原的模板类型,并且所有这些类型都是精确地以T的形式推导出来的,或者如果您想要一个没有模板的构造函数来接收精确的T类型的N值。

第一种情况很简单(如果可以使用C++17模板折叠;否则要复杂一点),因为您可以使用std::is_same

代码语言:javascript
复制
template <typename ... Types,
          typename std::enable_if<(sizeof...(Types) == N) 
              && (... && std::is_same<Types, T>::value), int>::type = 0>
explicit HasArray(Types ... s) : arr {{ s... }}
 { }

对于第二种情况,我提出了Jarod42解决方案的一个变体,它使用HasArray的专门化而不是中间类(编辑:添加了来自Jarod42本身的改进;谢谢!):

代码语言:javascript
复制
template<typename T, std::size_t N, typename = std::make_index_sequence<N>>
struct HasArray;

template<typename T, std::size_t N, std::size_t ... Is>
struct HasArray<T, N, std::index_sequence<Is...>>
 {
   static_assert( sizeof...(Is) == N , "wrong sequence size" );

   protected:
      std::array<T, N> arr;

   public:
      explicit HasArray(getType<T, Is> ... s) : arr {{ s... }}
       { }
 };

getType在哪里

代码语言:javascript
复制
template <typename T, std::size_t>
using getType = T;

第一种情况,

代码语言:javascript
复制
HasArray<std::uint32_t, 2> foo(7, 13);

给出编译错误,因为713被推断为int,而不是std::uin32_t

在第二种情况下,它编译,因为HasArray有一个构造函数

代码语言:javascript
复制
HasArray(std::uint32_t, std::uint32_t)

并将int转换为std::uint32_t

下面是第二种情况的完整编译C++14示例

代码语言:javascript
复制
#include <array>
#include <cstdint>
#include <type_traits>

template <typename T, std::size_t>
using getType = T;

template<typename T, std::size_t N, typename = std::make_index_sequence<N>>
struct HasArray;

template<typename T, std::size_t N, std::size_t ... Is>
struct HasArray<T, N, std::index_sequence<Is...>>
 {
   static_assert( sizeof...(Is) == N , "wrong sequence size" );

   protected:
      std::array<T, N> arr;

   public:
      explicit HasArray(getType<T, Is> ... s) : arr {{ s... }}
       { }
 };

int main ()
 {
   HasArray<std::uint32_t, 2> foo(7, 13);
 }
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54458449

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档