【问题标题】:Class template argument deduction for template type which is itself an argument for a template模板类型的类模板参数推导,它本身就是模板的参数
【发布时间】:2019-10-11 09:12:26
【问题描述】:

在另一个模板类型声明中使用的具有默认参数的模板类型是否支持类模板参数推导?以下代码不能同时使用 Clang/GCC 主干编译,它在定义 y 的行上失败:

#include <optional>

template <class T = char>
struct C {};

int main() {
    C x;
    std::optional<C> y;
}

(https://godbolt.org/z/SgxY90)

修改代码以读取std::optional&lt;C&lt;&gt;&gt; y 解决了这个问题,但我有点惊讶这是需要的。这是编译器问题,还是已知的语言限制?

【问题讨论】:

    标签: c++ templates c++17 optional


    【解决方案1】:

    编译器必须验证传递给模板的内容是否与预期的模板参数相匹配。现在考虑我要用你的例子写这个,你看不到foo

    foo<C> f;
    

    它是 CTAD 的一个实例,还是我传递了模板本身?因为已经可以将模板作为参数传递给其他模板。

    template< template<typename> class T > struct foo {};
    

    在该上下文中允许 CTAD 将使 C 的使用依赖于上下文。相反,模板名称在声明变量时没有其他用途。写的时候没有歧义……

    C c;
    

    ...这可能意味着 CTAD 以外的东西,所以这里允许。但是当模板名称用作模板参数时,上下文很重要。 C++ 已经有很多依赖于上下文的结构,所以添加更多通常是个坏主意。

    【讨论】:

    • 在您的示例中,我们看不到foo,但编译器必须在编译foo&lt;C&gt; f; 后才能看到它。那么到那时它应该能够确定是否有任何歧义并在有歧义的情况下给出错误?
    • @TonvandenHeuvel - 关键是,对foo 的一个小改动可能会以一种完全出乎意料的方式改变程序的语义。如果我要重构并说foo 现在接受一个类型,那么声明的含义将悄然改变!避免这种无声更改的可能性是 C++ 设计的支柱。
    • 我们可以说在模板参数的上下文中C 不是类型名,因为它是模板的标识符。即使它有一个默认参数,typename 也是C&lt;&gt;
    • @Swift-FridayPie - 现在就是这样。在其上添加 CTAD 将使其不再正确。
    猜你喜欢
    • 1970-01-01
    • 2020-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-26
    • 2014-01-29
    • 2023-03-31
    相关资源
    最近更新 更多