【问题标题】:Why is `const T&` not sure to be const?为什么`const T&`不确定是const?
【发布时间】:2019-06-26 02:17:43
【问题描述】:
template<typename T>
void f(T a, const T& b)
{
    ++a; // ok
    ++b; // also ok!
}

template<typename T>
void g(T n)
{
    f<T>(n, n);
}

int main()
{
    int n{};
    g<int&>(n);
}

请注意:b 属于const T&amp;++b 可以!

为什么const T&amp; 不确定是 const?

【问题讨论】:

    标签: c++ templates constants function-templates const-reference


    【解决方案1】:

    欢迎使用 const 和 reference collapsing。当您拥有const T&amp; 时,引用将应用于Tconst 也是如此。你给g点赞

    g<int&>(n);
    

    所以你已经指定Tint&amp;。当我们对左值引用应用引用时,两个引用合并为一个,所以int&amp; &amp; 变成了int&amp;。然后我们从[dcl.ref]/1 得到规则,它指出如果你将const 应用到一个引用上,它就会被丢弃,所以int&amp; const 就变成int&amp;(注意你实际上不能声明int&amp; const,它必须来自 typedef 或模板)。这意味着

    g<int&>(n);
    

    你真的在打电话

    void f(int& a, int& b)
    

    而且你实际上并没有修改常量。


    你打电话给g

    g<int>(n);
    // or just
    g(n);
    

    那么T 将是int,而f 将被标记为

    void f(int a, const int& b)
    

    由于 T 不再是一个引用,const&amp; 被应用到它,你会收到一个编译器错误尝试修改一个常量变量。

    【讨论】:

    • 这就是为什么存在像std::add_lvalue_reference 这样的类型特征,以确保以可预测的方式添加引用以防止这种痛苦。
    • 一种更容易理解的方法是写T const&amp;而不是const T&amp;(相同),然后将T替换为int&amp;
    • 我会重新排序这个答案的第一部分,因为在const T&amp; 类型中,首先const 适用于T,然后左值引用适用于结果那。 (如果规则相反,“const 应用于引用类型被忽略”规则将始终生效,const T&amp; 将始终与 T&amp; 含义相同。)
    • @aschepler 规则停止T&amp; const,而不是const T&amp;/T const &amp;
    • @NathanOliver 当我阅读这个答案时,您已经说过参考折叠规则“发生”在 const 折叠规则之前,我认为这是错误的。如果你有int &amp; const &amp;,那么你需要先应用const规则得到int &amp; &amp;,然后引用规则得到int&amp;。我同意第一位需要改写。也许英文“翻译”也是为了:“g&lt;T&gt; 的参数是对T 的常量引用。g&lt;int&amp;&gt; 的参数是对int 的引用的常量引用。对a 的常量引用引用只是一个引用。这在 C++ 中由 ..." 形式化
    【解决方案2】:

    我知道已经有一个公认的答案是正确的,但只是添加一点点,即使在模板领域之外,也只是在一般的函数声明中......

    ( const T& ) 
    

    不一样

    ( const T )
    

    在与第一个匹配的示例中,您有一个 const 引用。如果您确实想要一个不可修改的 const 值,请删除第二个示例中的引用。

    【讨论】:

    • Tint&amp;const T&amp;const T 都给出int&amp;
    • 我认为我想说的有误解;我在这里使用 T 而不是 template 参数。 T 只是用作任何数据类型:intfloatdouble 等。所以在我上面的示例中,T 永远不应该是int&amp;。我确实在模板领域之外做了特别说明。
    • 嗯,这听起来好像你在解释你可以在没有模板的情况下看到这个,这没有问题。但是你的最后一句话声称为 OP 的问题提供了一个解决方案,而这个问题肯定涉及模板。为比模板更广泛的模板问题提供解决方案很好。但是对模板不准确的模板问题的解决方案似乎无法回答问题。
    • 这也可能是不涉及模板的问题:using T = int&amp;; void f(const T&amp;); 声明 void f(int&amp;);
    • @aschepler 是的,但我指的不是using 子句;一般只是基本的函数声明。
    猜你喜欢
    • 2012-08-02
    • 2010-11-10
    • 2012-09-04
    • 2017-10-22
    • 2017-01-11
    • 1970-01-01
    • 2012-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多