本文介绍了如何模拟模板别名的推导指南?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下内容:

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

我们可以提供有关 my_array 的推导指南,例如

We can provide deduction guides for my_array, something like

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

现在,假设 my_array< T,2> 具有一些非常特殊的含义(但仅意味着接口&实现保持不变),所以我们想给它一个更合适的名称:

Now, suppose that my_array<T, 2> has some very special meaning (but only meaning, the interface & implementation stay the same), so that we'd like to give it a more suitable name:

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

事实证明,推导简单地不适用于模板别名,即会产生编译错误:

It turns out that deduction guides simply don't work for template aliases, i.e. this gives a compilation error:

float x, y;

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

我们仍然可以说 special< float>b 并开心.但是,假设 T 是一些冗长乏味的类型名称,例如 std :: vector< std :: pair< int,std :: string>> :: const_iterator .在这种情况下,在此处进行模板参数推导将非常方便.因此,我的问题是:如果我们真的希望 special 是等于 my_array< T,2> 的类型(在某种意义上是 ),而且我们真的希望演绎指南(或类似的指南)起作用,如何克服这一局限性?

We can still say special<float> b and be happy. However, suppose that T is some long and tedious type name, like e.g. std::vector<std::pair<int, std::string>>::const_iterator. In this case it will be extremely handy to have template argument deduction here. So, my question is: if we really want special to be a type equal (in some sense) to my_array<T, 2>, and we really want deduction guides (or something similar) to work, how can one overcome this limitation?

我事先为一个模棱两可的问题道歉.

I apologize in advance for a somewhat vaguely posed question.

我已经提出了两个解决方案,它们都有严重的缺点.

I've come up with a couple of solutions, both with serious disadvantages.

1)将 special 设为具有相同接口(即

1) Make special a separate unrelated class with the same interface, i.e.

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

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

此重复项看起来很尴尬.此外,与其编写类似

This duplication looks awkward. Furthemore, instead of writing functions like

void foo (my_array<T, N>);

我被迫重复他们

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

或要做

template <typename Array>
void foo (Array);

,并且依赖于此类的接口是相同的.我通常不喜欢这种代码(接受任何内容并完全依赖于鸭子输入).可以通过一些SFINAE/概念来改进它,但是仍然感到尴尬.

and rely on the interface of this classes being the same. I don't generally like this kind of code (accepting anything and relying solely on duck typing). It can be improved by some SFINAE/concepts, but this still feels awkward.

2)将 special 设为功能,即

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

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

No type duplication here, but now I cannot declare a variable of type special, since it is a function, not a type.

3)为 special 保留模板别名,但提供一个类似于C ++ 17的 make_special 函数:

3) Leave special a template alias, but provide a pre-C++17-like make_special function:

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

在某种程度上它可以工作.但这仍然不是推论指南,并且将使用推论指南的类与 make_XXX 函数混合使用会令人感到困惑.

It works, to some extent. Still, this is not a deduction guide, and mixing classes that use deduction guides with this make_XXX functions sounds confusing.

4)按照@NathanOliver的建议,使 special 继承自 my_array :

4) As suggested by @NathanOliver, make special inherit from my_array:

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

这使我们能够为 special 提供单独的推导指南,并且不涉及代码重复.但是,编写类似

This enables us to provide separate deduction guides for special, and no code duplication involved. However, it may be reasonable to write functions like

void foo (special<int>);

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

which unfortunately will fail to accept my_array<2>. It can be fixed by providing a conversion operator from my_array<2> to special, but this means we have circular conversions between these, which (in my experience) is a nightmare. Also special needs extra curly braces when using list initialization.

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

Are there any other ways to emulate something similar?

推荐答案

简单的答案是等到C ++ 20.届时很有可能将学习类模板的推导(以及聚合和继承的构造函数,请参见P1021 ).

The easy answer is to wait until C++20. It's pretty likely that class template deduction will be learn how to look through alias templates by then (as well as aggregates and inherited constructors, see P1021).

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

Beyond that, (1) is definitely a bad choice. But choosing between (2), (3), and (4) largely depends on your use cases. Note that for (4), deduction guides aren't inherited until P1021 either, so you'd need to copy the base class' deduction guides if you go the inheritance route.

但是您还错过了第五种选择.无聊的人:

But there's also a fifth option that you missed. The boring one:

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

有时候,足够好了吗?

这篇关于如何模拟模板别名的推导指南?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-13 13:23