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

时间:2018-08-16 09:22:09

标签: c++ templates c++17 stdarray

给出一个功能模板,其签名在多个位置包含一个长名称,例如一个函数模板,其中包含两个std::array,其中包含大小为3 std::array,并且返回一个,

// 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;
}

为防止滥用附加模板类型参数(显然根本不会被客户端使用),该函数可以应用编译时检查以验证其实例化是否导致使用了参数的默认类型(通过{{ 1}})。

这个问题的全部重点是减少功能模板签名中的代码重复(当重复确实会降低可读性时)。这种方法对我来说似乎很自然,但是我不确定是否会出现我看不见的任何问题。

谢谢。

1 个答案:

答案 0 :(得分:1)

我看不到您的其他类型名称解决方案有问题(除了您刚才看到的存在这种类型的风险外)。

但是我提出了一个完全不同的解决方案:使foo()收到通用类型名AA(对于Array-Array)

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

,如果需要,可以在函数内提取T中的内部类型(旧的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

 }