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

Using additional template type parameters as type alias declarations to use in function's signature

本文关键字:类型 声明 别名 函数 其他 类型参数      更新时间:2023-10-16

给定一个函数模板,其签名在多个位置包含冗长的名称,例如,一个函数模板采用两个包含自身大小 3std::arrays 的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;
}

为了防止滥用其他模板类型参数(显然客户端根本不会使用它(,该函数可能会应用编译时检查来验证其实例化是否导致使用参数的默认类型(通过if constexpr (std::is_same<...>())(。

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

谢谢。

我没有看到您的附加类型解决方案有问题(除了您刚刚看到的所解释类型的风险(。

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

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
}