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

使用其他模板类型参数作为要在函数签名中使用的类型别名声明

  •  0
  • Jersey  · 技术社区  · 7 年前

    给定一个函数模板,其签名在多个位置包含长名称,例如,一个函数模板取两个 std::array S包含自己的尺寸-3 STD::阵列 还有还退回一个,

    // Clumsy - requires multiple line breaks
    template <typename T, std::size_t n>
    typename std::array<std::array<T, 3>, n> 
    foo(const typename std::array<std::array<T, 3>, n>& points_a, 
        const typename std::array<std::array<T, 3>, n>& points_b)
    {
        typename std::array<std::array<T, 3>, n> result;
        // .. process ..   
        return result;
    }
    

    这样做是不明智的吗 引入其他具有派生默认值的冗余模板类型参数,以便使用这些类型参数的名称使函数的签名更清晰。 ?在这个例子中 typename Points = typename std::array<std::array<T, 3>, n> 将添加到模板参数:

    // Better
    template <typename T, std::size_t n, typename Points = typename std::array<std::array<T, 3>, n>>
    Points bar(const Points& points, const Points& offsets)
    {
        Points result;
        // .. process ..   
        return result;
    }
    

    为了防止错误使用额外的模板类型参数(显然客户机根本不应该使用该参数),该函数可以应用编译时检查,以验证其实例化是否导致使用参数的默认类型(通过 if constexpr (std::is_same<...>()) )

    这个问题的关键是减少函数模板签名中的代码重复(当重复确实减少了易读性时)。这种方法对我来说似乎很自然,但我不确定是否会出现我看不见的问题。

    谢谢您。

    1 回复  |  直到 7 年前
        1
  •  1
  •   max66    7 年前

    我看不出您的附加类型名解决方案有什么问题(除了您刚才看到的那种类型的风险)。

    但我提出了一个完全不同的解决方案:制造 foo() 接收通用类型名 AA (用于数组数组)

    template <typename AA>
    AA foo (AA const & points_a, AA const & points_b)
    

    如果需要,在函数内部可以提取内部类型(旧的 T 在A using

    using T = typename AA::value_type::value_type;
    

    并且,利用 std::tuple_size 对于数组,也是外部维度(旧的 n )

    static constexpr auto n { std::tuple_size<AA>::value };
    

    如果你还想把 std::array 是3号的,您可以通过sfinae(使用 std::enable_if_t 对于返回的类型)或通过 static_assert() 在函数内部

    static_assert( std::tuple_size<typename AA::value_type>::value == 3u );
    

    下面是一个完整的工作示例

    #include <array>
    #include <utility>
    #include <iostream>
    
    template <typename AA>
    AA foo (AA const & points_a, AA const & points_b)
     {
       using T = typename AA::value_type::value_type;
    
       static constexpr auto n { std::tuple_size<AA>::value };
    
       static_assert( std::tuple_size<typename AA::value_type>::value == 3u );
    
       std::cout << std::is_same<T, int>::value << ' ' << n << std::endl;
    
       AA result;
    
       // .. process ..   
    
       return result;
     }
    
    int main ()
     {
       std::array<std::array<int, 3u>, 5u>  a;
       std::array<std::array<long, 3u>, 7u>  b;
       std::array<std::array<long, 5u>, 9u>  c;
    
       foo(a, a); // print 1 5
       foo(b, b); // print 0 7
       // foo(c, c); // compilation error
    
     }