从c++ 17开始,构造函数的模板形参推导是否允许显式指定一些类模板实参?

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

本文关键字:许显式 实参 是否 开始 c++ 构造函数 形参      更新时间:2023-10-16

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

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

虽然这种结构是函数中模板形参推导的自然结果,但我找不到任何这种用法的例子。也许是因为在具有可变模板参数的类的情况下存在歧义?

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

然而,这种方式引入的语法不能替代太好的"make_*"包装器(参见N3602),因为我们可以使用该功能…

显然不是。P0091的介绍声称它可以,但实际的措辞说的完全不同:

与类模板对应的模板名,后跟带括号的表达式列表…

这就排除了使用template-name +一些参数和"括号表达式列表"的情况。在语法上,它也被排除在措辞的其他部分。

因此,不可能在推导其他参数的同时指定某些参数

是的,但是间接的。

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

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

使用c++ 17中的演绎指南和一个接受helper类型的附加构造函数。当你的类有很多模板参数时,这通常更容易。

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

编辑,添加元组 的示例

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

使用这里的编译器资源管理器,请注意推导的和定义的模板参数都是正确构造的:

https://godbolt.org/z/VrT9Lf

用法:

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