【问题标题】:Is it possible to declare template parameters within the template arguments of another template parameter?是否可以在另一个模板参数的模板参数中声明模板参数?
【发布时间】:2021-12-21 17:44:51
【问题描述】:

我正在尝试创建一个将std::array 作为模板参数的类模板。目前声明如下:

template<typename T, std::size_t N, std::array<std::size_t, N> A>
class Foo {
    ...
}

然而,这很不幸,因为我通常会使用初始化列表来初始化 A,这使得指定 N 的需要变得乏味且多余:

// Current
Foo<int, 3, {5, 3, 4}> bar;

// Preferred
Foo<int, {5, 3, 4}> baz;

我曾尝试使用类似于模板模板参数的东西无济于事:

template<typename T, template<std::size_t N> std::array<std::size_t, N> A>

有没有办法完成我正在尝试做的事情,或者通过将 N 放在参数列表中的 A 之后来“隐藏”它?

【问题讨论】:

  • 关于“我通常会用初始化列表初始化arr”,arr 是什么?另外,请说明您将如何创建 Foo 的实例。
  • @cigien 已编辑,谢谢
  • 为什么不将using A = std::array&lt;std::size_t, N&gt;; 添加到您的模板类中?
  • @paddy 到底有什么帮助?我不相信这会让您将数组指定为模板参数,对吗?
  • 如果您没有义务使用数组作为参数:template&lt;typename T, size_t... ARR_ELEMENTS&gt;。然后你可以使用static constexpr std::array&lt;size_t, sizeof...(ARR_ELEMENTS)&gt; A = {ARR_ELEMENTS...}; 在类中创建数组。

标签: c++ arrays templates c++20


【解决方案1】:

可以选择添加包装器,所以下面的代码可以工作:

Foo2<as_std_array<5, 3, 4>> baz2;

as_std_array 被定义为:

template<auto item, auto... items>
struct as_std_array {
    using TYPE = std::common_type_t<decltype(item), decltype(items)...>;
    constexpr static std::size_t SIZE = sizeof...(items)+1;
    constexpr static auto ARRAY = std::array<TYPE, SIZE>{item, items...};
};

而Foo,Foo2为:

template<std::size_t N, typename T, std::array<T, N> A>
struct Foo {
    constexpr static auto ARRAY = A;
};

template<typename T>
class Foo2: public Foo<T::SIZE, typename T::TYPE, T::ARRAY>{};

然后以下工作:

Foo2<as_std_array<5, 3, 4>> baz2;    
static_assert(baz2.ARRAY == std::array{5, 3, 4});

Link to code

【讨论】:

    【解决方案2】:

    您也许可以使用 c++20 auto 模板参数:

    template<typename T, auto A>
    

    使用 Boost 对类型进行分解的现场演示:

    Live On Compiler Explorer

    #include <array>
    #include <boost/core/demangle.hpp>
    #include <iostream>
    
    template<typename T, auto A>
    struct Foo {
        void bar() const {
            std::cout << boost::core::demangle(typeid(decltype(A)).name()) << "\n";
        }
    };
    
    
    int main() {
        Foo<int, std::array{3,4,7}> f;
        Foo<int, std::array{'a', 'b'}> g;
    
        f.bar();
        g.bar();
    }
    

    打印

    std::array<int, 3ul>
    std::array<char, 2ul>
    

    可变参数包

    否则我建议将数组元素作为一个包传递:

    template<typename T, auto... A>
    

    看Live Online (C++17)

    #include <type_traits>
    #include <iostream>
    
    template<typename T, auto...>
    struct Foo {
        void bar() const {
            std::cout << __PRETTY_FUNCTION__ << "\n";
        }
    };
    
    
    int main() {
        Foo<int, 3,4,7> f;
        Foo<int, 'a', 'b'> g;
    
        f.bar();
        g.bar();
    }
    

    打印

    void Foo<T, <anonymous> >::bar() const [with T = int; auto ...<anonymous> = {3, 4, 7}]
    void Foo<T, <anonymous> >::bar() const [with T = int; auto ...<anonymous> = {'a', 'b'}]
    

    【讨论】:

    • 对于 variadic-pack 示例,显式使用 std::size_t... 包可能更有意义,因为这是问题中 std::array 的值类型。否则Foo 现在还必须确保所有参数都可以转换为正确/所需的类型
    • @Human-Compiler 问题是,有一个使用size_t 的示例好吧,但没有说该类型不是硬编码的。但是,是的,如果可以的话,narrow your contracts!
    • auto 模板参数是 C++17 特性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-22
    • 1970-01-01
    • 1970-01-01
    • 2012-08-07
    • 1970-01-01
    • 2016-12-01
    相关资源
    最近更新 更多