自 C++17 允许显式指定某些 class 模板参数以来,构造函数的模板参数推导是否可用?

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

除了构造函数的模板参数推导的最明显用法外,我可以想象一些更复杂的用例,我们只推导模板的部分参数class例如:

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

尽管这种构造是在函数中扣除模板参数的自然结果,但我找不到这种用法的任何示例。 也许是因为 classes 带有可变模板参数的情况下的歧义?

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

然而,这种引入语法的方式不会替代太好的 "make_*" 包装器(参见 N3602),其中功能对我们可用...

显然不是。 P0091 的介绍声称它确实如此,但实际的 措辞 却完全不同:

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

这排除了模板名称 + 一些参数和 "parenthesized expression-list" 的使用。其他部分的写法也从语法上排除了。

所以不,在推导其他参数的同时指定一些参数是不可能的。

是的,但是是间接的。

对于有类似问题但想要有效解决方法而不是语言律师的其他人:

这可能是一个深奥的例子,但它实际上非常接近这种技术在现实世界中的应用。

您使用了来自 C++17 的演绎指南和一个接受辅助类型的附加构造函数。当你有一个 class 有许多模板参数时,这通常更容易推导。

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

可以在这里玩:

https://godbolt.org/z/E8d1Dt

编辑,为元组添加示例

以元组为例:

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

使用此处的编译器资源管理器,请注意推导和定义的模板参数均已正确构造:

https://godbolt.org/z/VrT9Lf

用法:

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