具有 std::array 大小类型的派生模板类

Posted

技术标签:

【中文标题】具有 std::array 大小类型的派生模板类【英文标题】:Derived template class with std::array size type 【发布时间】:2021-08-25 07:10:46 【问题描述】:

我正在使用C++17 并且有一个模板类,它对模板变量类型有限制。我想添加一个派生类,该类还接受std::array 参数并模板化数组的大小。

template <typename T,
typename U = std::enable_if<std::is_same_v<T, int> || std::is_same_v<T, bool>>>
class Base 
public:
    Base(T param1) : value(param1) 

    T value;
;


template <typename T,
typename U = std::enable_if<std::is_same_v<T, int> || std::is_same_v<T, bool>>,
typename N = unsigned int>
class Derived : public Base<T, U>

public:
    Derived(T param1, std::array<std::pair<T, bool>, N>&& param2) :
        Base(param1),
        arr(std::move(param2)) 

    std::array<std::pair<T, bool>, N> arr;
;

// We can use Base as such
Base<int> b  23 ;
// I want to use Derived in such a way
Derived<int, 2> d 0, 1, true, 2, false ;

但是,我在构建或创建派生类的实例时遇到了麻烦。任何帮助表示赞赏!

编辑: 在通过切换变量和取消模板化 N 提供的建议中添加。 这是一个 MRE https://godbolt.org/z/MGj5YdbxP 创建派生实例时出现新错误。

编辑2: 我知道 sfinae 并会解决这个问题。有没有办法让它为 r-val 参考工作,所以我可以移动第二个参数? https://godbolt.org/z/YxYssKPn3 假设我还支持将被销毁的 T 的大型 std::string 类型。

【问题讨论】:

请提供minimal reproducible example,包括完整的错误消息 也许交换U,N 的位置并制作N std::size_t 而不是类型?这样来自Derived&lt;int,2&gt; 的两个被分配给U 而不是N 第二个参数用 && 没有多大意义(类型不会从移动中获得太多收益)。如果你通过了std::move(a)。更通常的做法是通过值或const &amp; 获取 Derived 构造函数的第二个参数。 godbolt.org/z/h8YsE8xsG @alfC 如果我也支持 T 的 std::string 类型并且想要移动很快就会被破坏的很长的字符串怎么办。有没有办法让它为 r-val ref 工作? 问得好,我认为此举不会自动通过std::array 传递(也许是通过std::pair)。我必须在实际代码中看到它。 【参考方案1】:

只需重新排序参数,并使用非类型模板参数:

template <typename T,
          std::size_t N,
          std::enable_if_t<std::is_same_v<T, int> || std::is_same_v<T, bool>, int> = 0>
class Derived : public Base<T>

// ...
;

注意:typename U = std::enable_if&lt;condition&gt; 不启用 SFINAE。 您需要typename U = std::enable_if_t&lt;condition&gt;typename U = typename std::enable_if&lt;condition&gt;::type。 该表单可能被劫持(就像您使用Base&lt;T, U&gt; 一样);更喜欢std::enable_if_t&lt;condition, int&gt; = 0

【讨论】:

是的,我将使用 enable_if_t 并知道它是如何工作的,谢谢。这不是我在这个问题上遇到的问题。【参考方案2】:
Derived(T param1, std::array<std::pair<T, bool>, N>&& param2)

此构造函数中用于std::array 的第二个模板参数N 在这里是一个类型(模板参数),而std::array 需要一个非类型模板的有效参数std::size_t 类型的参数。

您似乎想在 std::size_t 类型的非类型模板参数上参数化您的 Derived 类型。

【讨论】:

【参考方案3】:

IIRC,我对您的代码进行了 2 处更改:

1.来自 Derived(T param1, std::array&lt;std::pair&lt;T, bool&gt;, N&gt;&amp;&amp; param2) : Base(param1), Derived(T param1, std::array&lt;std::pair&lt;T, bool&gt;, N&gt;&amp;&amp; param2) : Base&lt;T,U&gt;(param1),

2.来自template &lt;typename T, typename U = std::enable_if&lt;std::is_same_v&lt;T, int&gt; || std::is_same_v&lt;T, bool&gt;&gt;, typename N = unsigned int&gt;

template &lt;unsigned int N ,typename T, typename U = std::enable_if&lt;std::is_same_v&lt;T, int&gt; || std::is_same_v&lt;T, bool&gt;&gt; &gt;

代码如下:


#include<array>
#include<map>

template <typename T,
    typename U = std::enable_if<std::is_same_v<T, int> || std::is_same_v<T, bool>>>
    class Base 
    public:
        Base(T param1) : value(param1) 

        T value;
;


template <unsigned int N
    ,typename T,
    typename U = std::enable_if<std::is_same_v<T, int> || std::is_same_v<T, bool>>
    >
    class Derived : public Base<T, U>

public:
    Derived(T param1, std::array<std::pair<T, bool>, N>&& param2) :
        Base<T,U>(param1),
        arr(std::move(param2)) 

    std::array<std::pair<T, bool>, N> arr;
;

// We can use Base as such
Base<int> b 23 ;

int main() 
// I want to use Derived in such a way
    Derived<2, int> d 0,  std::make_pair(1, true),  2, false   ;

    return 0;

【讨论】:

感谢您的回答!我喜欢你保留 r-val ref 的方式,但是有没有办法通过传入 std::array 而不是在 d 中定义它来让它工作? 使用std::move? ``` std::array<:pair bool>, 2> myarray;; myarray[0] = std::make_pair(1, true); myarray[1] = std::make_pair(2, false); // 我想以这样的方式使用 Derived Derived d( 0, std::move(myarray) ); ``` 看来我可能不得不使用 std::move... 谢谢!

以上是关于具有 std::array 大小类型的派生模板类的主要内容,如果未能解决你的问题,请参考以下文章

选择具有派生类型的基类型的模板特化

具有通用模板基类型的 STL 容器,接受派生类型

在 C++11 中具有对齐元素的 std::array 类型

变长 std::array 像

具有派生类的模板化数据类型

为啥 std::array::size constexpr 具有简单类型(int,double,...)而不是 std::vector (GCC)?