C++17中的部分类模板参数推导

12
在下面的示例中,我们使用C++17的功能“类模板参数推导”来推断val的类型为Base<int, double, bool>
template<class T, class U, class V>
struct Base {
    Base(T, U) { };
    Base(T, U, V) { };
    Base(V) { };
};

void func() {
    Base val(1, 4., false);
}

现在,是否有可能部分指定模板参数,让剩余的参数自动推导?实际上就像这样:像这样
Base<V = bool> val1(1, 4.);        // U & V deduced --> Base<int, double, bool>
Base<T = bool, T = int> val2(5.);  // V deduced     --> Base<bool, int, double>

我试过例如。
template<class T, class U> using Base2 = Base<T, U, double>;

void func() {
    NewBase2 val(1, 2);
}

但它无法编译:'Base2':使用别名模板需要模板参数列表
部分推导是否可能?如果直接不可能,是否有任何好的解决方法?

在给定的示例中,您可以指定 T 并且有 UV 推导出来,或者指定 TU 并且有 V 推导出来。看到规律了吗?在 C++ 中拥有命名模板参数会很好,但不幸的是我们没有。 - Sam Varshavchik
2个回答

15

CTAD(类模板参数推导)目前是一个全有或全无的过程。您可以不指定任何参数,让编译器推导所有参数,或者您可以指定所有参数,使编译器退出循环。

有一篇论文(P1021R0)要求实现部分特化,但它尚未被接受。 有一篇论文要求偏特化,但在修订后已被删除。 最新版本的提案仍包括在使用别名时启用CTAD的提议。


根据@Barry的说法,在C++20的工作草案中增加了对别名模板(P1814)和聚合体(P1816)的支持,但尚未添加部分CTAD或继承构造函数的支持。


1
最新版本的论文是P1021,它被拆分成两个不同的论文:P1814用于别名模板P1816用于聚合体。这两篇论文都已经被添加到C++20的工作草案中。将不会有任何部分CTAD,也不支持继承构造函数。 - Barry
@Barry 谢谢你提供的资源。我会添加进去的。 - NathanOliver

11
您可以按照以下方式添加扣除指南:
template<class T, class U>
Base(T, U) -> Base<T, U, bool>;

template<class V>
Base(V) -> Base<bool, int, V>;

这使得

Base val1(1, 4.); // Base<int, double, bool>
Base val2(5.);    // Base<bool, int, double>

如果您想指定“默认”的模板,可以使用旧的方式与make_一起使用。

template <typename V, typename T, typename U>
Base<T, U, V> make_Base(T t, U u)
{
    return Base<T, U, V>{t, u};
}

template <typename T, typename U, typename V>
Base<T, U, V> make_Base(V v)
{
    return Base<T, U, V>{v};
}


auto val1 = make_Base<bool>(1, 4.);   // Base<int, double, bool>
auto val2 = make_Base<bool, int>(5.); // Base<bool, int, double>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接