9

考虑以下:

template <typename T, std::size_t N>
struct my_array
{
    T values[N];
};

我们可以提供扣除指南my_array,例如

template <typename ... Ts>
my_array (Ts ...) -> my_array<std::common_type_t<Ts...>, sizeof...(Ts)>;

现在,假设它my_array<T, 2>有一些非常特殊的含义(但只是含义,接口和实现保持不变),所以我们想给它一个更合适的名字:

template <typename T>
using special = my_array<T, 2>;

事实证明,推导指南根本不适用于模板别名,即这会产生编译错误:

float x, y;

my_array a { x, y }; // works
special b { x, y }; // doesn't

我们仍然可以说special<float> b并感到高兴。但是,假设这T是一些冗长乏味的类型名称,例如 eg std::vector<std::pair<int, std::string>>::const_iterator。在这种情况下,在这里进行模板参数推导将非常方便。所以,我的问题是:如果我们真的想special成为(在某种意义上my_array<T, 2>

我提前为一个有点含糊的问题道歉。


我想出了几个解决方案,但都有严重的缺点。

1)special用相同的接口制作一个单独的不相关的类,即

template <typename T>
struct special
{
    T values[2];
};

template <typename T>
special (T, T) -> special<T>;

这种重复看起来很尴尬。此外,而不是编写函数,如

void foo (my_array<T, N>);

我被迫要么复制它们

void foo (my_array<T, N>);
void foo (special<T>);

或做

template <typename Array>
void foo (Array);

并且依赖于这些类的接口是相同的。我一般不喜欢这种代码(接受任何东西并完全依赖鸭子打字)。它可以通过一些 SFINAE/概念来改进,但这仍然感觉很尴尬。

2)做special一个功能,即

template <typename T>
auto special (T x, T y)
{
    return my_array { x, y };
}

这里没有类型重复,但现在我不能声明 type 的变量special,因为它是一个函数,而不是一个类型。

3) 保留special模板别名,但提供类似 C++17 之前的make_special函数:

template <typename T>
auto make_special (T x, T y)
{
    return my_array { x, y };
    // or return special<T> { x, y };
}

它在某种程度上有效。尽管如此,这不是一个演绎指南,并且将使用演绎指南的类与此make_XXX功能混合听起来令人困惑。

4) 正如@NathanOliver 所建议的,使special继承自my_array

template <typename T>
struct special : my_array<T, 2>
{};

这使我们能够为 提供单独的推导指南special,并且不涉及代码重复。但是,编写如下函数可能是合理的

void foo (special<int>);

不幸的是,这将无法接受my_array<2>。它可以通过提供转换运算符 from my_array<2>to 来解决special,但这意味着我们在这些之间进行循环转换,这(以我的经验)是一场噩梦。使用列表初始化时还需要special额外的花括号。


还有其他方法可以模仿类似的东西吗?

4

1 回答 1

5

简单的答案是等到 C++20。到那时,类模板推导很可能会学习如何查看别名模板(以及聚合和继承的构造函数,请参阅P1021)。


除此之外,(1)绝对是一个糟糕的选择。但是在 (2)、(3) 和 (4) 之间进行选择很大程度上取决于您的用例。请注意,对于 (4),推导指南也不会在 P1021 之前被继承,因此如果您走继承路线,则需要复制基类的推导指南。

但是您还错过了第五个选项。无聊的一个:

special<float> b { x, y }; // works fine, even in C++11

有时候,这就够了?

于 2019-01-14T00:49:12.590 回答