How to emulate deduction guides for template aliases?

旧时模样 提交于 2021-02-04 17:53:06

问题


Consider the following:

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

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)>;

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

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) 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>);

I'm forced either to duplicate them

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

or to do

template <typename Array>
void foo (Array);

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) Make special a function, i.e.

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

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

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

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) As suggested by @NathanOliver, make special inherit from my_array:

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

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>);

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?


回答1:


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).


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

Sometimes, that's good enough?



来源:https://stackoverflow.com/questions/54173048/how-to-emulate-deduction-guides-for-template-aliases

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!