Will template parameter deduction for constructors available since C++17 allow explicitly specify some of the class template arguments?

拟墨画扇 提交于 2019-12-22 04:43:17

问题


Apart from the most obvious usage of template parameter deduction for constructors, I can imagine some more complex use cases where we deduce only part of the parameters of the template class e.g.:

std::pair<int> p(1, 2); // std::pair<int, int>

Although this construct would be natural consequence of the deduction of template parameters in functions I couldn't find any example of this kind of usage. Maybe it's because of the ambiguity in case of classes with variadic template arguments?

std::tuple<int> t(1, 2, 3); // std::tuple<int, int, int>

However this way introduced syntax wouldn't substitute too good "make_*" wrappers (cf. N3602) where the functionality is available for us...


回答1:


Apparently not. P0091's introduction claims that it does, but the actual wording says quite differently:

A template-name corresponding to a class template followed by a parenthesized expression-list...

This rules out the use of a template-name + some arguments and a "parenthesized expression-list". It is also ruled out grammatically in other parts of the wording.

So no, it won't be possible to specify some arguments while deducing others.




回答2:


Yes, but indirectly.

For other people who have a similar problem but want a valid work around, not a language lawyer:

This might be an esoteric example, but it actually matches very closely a real world application of this technique.

You use a deduction guide, from C++17 and an additional constructor which accepts a helper type. This is often still easier when you have a class with many many template arguments that should mostly be deduced.

https://en.cppreference.com/w/cpp/language/class_template_argument_deduction

template <std::size_t v>
struct SizeT{};

template <std::size_t v, typename T>
struct PrintToBuffer
{
    T const Dunno;

    PrintToBuffer(T const & pInput) : 
        Dunno(pInput)
    {}
    //This works for any class, as it just forwards to another constructor
    template <typename ... Args>
    PrintToBuffer(SizeT<v>, Args && ... pInput) : 
        PrintToBuffer(std::forward<Args>(pInput)...) 
    {}

    void Print(std::array<char, v> & pOutput)
    {
        for (auto & c : pOutput)
            c = Dunno;
    }
};

This can be played around with here:

https://godbolt.org/z/E8d1Dt

EDIT, Adding an example for tuple

And for an example with tuple:

template <typename ... Args>
struct Types{};

template <typename ... T>
struct Tuple : std::tuple<T...>
{
    using base_t = std::tuple<T...>;
    using base_t::base_t;

    template <typename ... Ignore>
    Tuple(Types<Ignore...>, T && ... pInput) : base_t(std::forward<T>(pInput)...) {}
};

template <typename ... Defined, typename ... Args>
Tuple(Types<Defined...>, Defined && ..., Args&& ...) -> Tuple<Defined..., Args...>;

With the compiler explorer here, note that both the deduced and defined template arguments are correctly constructed:

https://godbolt.org/z/VrT9Lf

Usage:

auto my_tuple = Tuple(Types<int, short>{}, 1, 1, 'a');



来源:https://stackoverflow.com/questions/39067388/will-template-parameter-deduction-for-constructors-available-since-c17-allow-e

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