代码之家  ›  专栏  ›  技术社区  ›  Carson

C++模板化可选构造函数

  •  1
  • Carson  · 技术社区  · 2 年前

    初步信息

    我正在实现一个队列。我有一个 Vec 类,看起来如下:

    #include <cstddef>
    #include <span>
    
    template<typename T, size_t Extent, bool Dynamic = (Extent == std::dynamic_extent)>
    class Vec {
    public:
        constexpr size_t capacity(void) const;
        ~Vec();
    };
    
    template<typename T, size_t Extent>
    class Vec<T, Extent, true> {
        // Dynamic version
    public:
        Vec(size_t capacity);
    };
    
    template<typename T, size_t Extent>
    class Vec<T, Extent, false> {
        // Statically-sized version of the class
    public:
        constexpr Vec() = default;
    };
    

    换句话说, Vec 可以用 constexpr Vec() 当Extent= std::dyanmic_extent 。否则,必须传入一个大小,并且构造函数为 Vec(size_t capacity) 。这与提供的api类似 std::span

    问题

    我如何将其包含在新的类中, Queue ,这样我就可以在两个类之间共享大部分功能,但仍然有专门的actor。例如,我想写以下内容:

    template<typename T, size_t Extent = std::dynamic_extent>
    class Queue {
    public:
        template</* only enable if Extent != std::dynamic_extent */>
        constexpr Queue() {}
    
        template</* only enable if Extent == std::dynamic_extent */>
        Queue(size_t size) : m_slots(size) {}
    
        // Other methods...
    private:
        Vec<T, Extent> m_slots;
        // Other fields ...
    };
    

    我知道,我可以添加一个 bool Dynamic 参数匹配 Vec<T> ,但我需要重复每个类中的所有字段,并提供重复的函数定义。

    我尝试了几种不同的模板表达式变体(仅适用于 constexpr Queue() 显示了,的表达式 Queue(size_t size) 只是明显的反转)。

    尝试1:未命名,默认参数,可选无效

    template<typename = typename std::enable_if_t<Extent != std::dynamic_extent>>
    constexpr Queue() {}
    

    尝试2:尝试模仿 the c++ docs on std::enable_if

    template<std::enable_if_t<Extent != std::dynamic_extent, bool> = true>
    

    这两次尝试都未能编译,并发出警告:

    /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/type_traits:2608:44: error: no type named 'type' in 'std::enable_if<false, bool>'; 'enable_if' cannot be used to disable this declaration
     2608 |     using enable_if_t = typename enable_if<_Cond, _Tp>::type;
          |                                            ^~~~~
    ../src/queues/spsc.hh:34:16: note: in instantiation of template type alias 'enable_if_t' requested here
       34 |         template<std::enable_if_t<Extent == std::dynamic_extent, bool> = true>
          |
    

    我如何实现此行为?有没有我没有看到的更好的模式?

    链接

    我已经在中复制了这个问题,通过我的两次尝试 this godbolt

    1 回复  |  直到 2 年前
        1
  •  1
  •   Remy Lebeau    2 年前

    如果您查看cppreference的文档 std::span 's constructor ,您将看到它是如何使用的 std::dynamic_extent 在C++20中限制它的一些构造函数。仅供参考,它根本没有在模板参数中使用SFINAE,而是使用新的 explicit(expression) 取而代之的功能,例如:

    constexpr span() noexcept;
    
    template< class It >
    explicit(extent != std::dynamic_extent)
    constexpr span( It first, size_type count );
    
    template< class It, class End >
    explicit(extent != std::dynamic_extent)
    constexpr span( It first, End last );
    
    template< std::size_t N >
    constexpr span( std::type_identity_t<element_type> (&arr)[N] ) noexcept;
    
    template< class U, std::size_t N >
    constexpr span( std::array<U, N>& arr ) noexcept;
    
    template< class U, std::size_t N >
    constexpr span( const std::array<U, N>& arr ) noexcept;
    
    template< class R >
    explicit(extent != std::dynamic_extent)
    constexpr span( R&& range );
    
    template< class U, std::size_t N >
    explicit(extent != std::dynamic_extent && N == std::dynamic_extent)
    constexpr span( const std::span<U, N>& source ) noexcept;
    
    constexpr span( const span& other ) noexcept = default;
    
    推荐文章