【问题标题】:forcing template type to be reference by deduction强制模板类型通过推导被引用
【发布时间】:2015-08-04 09:01:25
【问题描述】:

假设我有一个函数func

template<typename T>
auto func(T arg){
    std::cout << std::boolalpha;
    std::cout << "T is ref: " << std::is_reference<T>::value << '\n';
}

有没有一种方法可以强制将T 推断为引用类型,而无需显式指定模板参数?

就像能够写出这样的东西:

auto main() -> int{
    auto x = 5;
    func(std::ref(x));
}

但不必专门针对std::reference_wrapper

static_casting 不会阻止 int&amp; 衰减为 int for T

假设我不能更改函数签名。

【问题讨论】:

  • auto func(T&amp;&amp; arg)?
  • @cpplearner 我知道我可以重新编写函数。这个问题纯粹是出于好奇。

标签: c++ templates c++14 language-lawyer


【解决方案1】:

假设我无法更改函数签名。

签名

template<typename T>
auto func(T arg) { ... }

永远不会推断引用,因为类型推断适用于参数表达式的类型,并且来自 [expr]:

如果表达式最初的类型为“引用T”(8.3.2、8.5.3),则该类型在之前调整为T 任何进一步的分析。

也就是说,模板推导仅在未明确提供模板参数时发生。所以你可以明确指定T

auto main() -> int{
    auto x = 5;
    func<int&>(x); // T = int&
}

否则,您可以在两者之间添加一个中间步骤:

template <typename T>
auto func_helper(T&& arg) {
    return func<T>(std::forward<T>(arg));
               ↑↑↑
}

因为,在 [temp.deduct.call]:

如果 P 是转发引用并且参数是 lvalue,类型“对A的左值引用”用于代替A进行类型推导。

所以如果func_helper被一个左值调用,模板参数P会被推导出来作为引用。在您的示例中:

func_helper(x);

T 将被推导出为int&amp;,因此我们显式调用与之前相同的函数:func&lt;int&amp;&gt;

func_helper(5);

T 会被推导出为int,我们会调用func&lt;int&gt;,就像我们直接调用func 一样。

【讨论】:

    【解决方案2】:

    注意:此答案已因后期编辑声明 OP 无法修改该功能而失效。


    类型推导和引用折叠是你需要的:

    template<class T>
    auto func(T&&) {
        std::cout << std::boolalpha << "T is ref: " << std::is_reference<T>::value << '\n';
    }
    
    int main() {
        func(5);
        int i = 7;
        func(i);
        int const j = 9;
        func(j);
    }
    

    输出:

    T is ref: false
    T is ref: true
    T is ref: true
    

    【讨论】:

    • 第一个不应该是右值引用吗?
    • @BЈовић:它会调用func(int&amp;&amp;),所以Tint
    • @BЈовић 看看this page,我无法解释得更好。
    • @Quentin Jarod42 的评论是正确的。函数参数类型是int&amp;&amp;,但T是int
    • 在第二种情况下,T 将是 int&amp;t 将是 int&amp;&amp;&amp; = int&amp;
    【解决方案3】:
    #include <iostream>
    #include <type_traits>
    #include <iomanip>
    
    using namespace std;
    
    
    template<typename T>
    auto func(T arg)
    {
        std::cout << std::boolalpha;
        std::cout << "T if ref: " << std::is_reference<decltype(arg)>::value << "\n";
    }
    
    template<class T>
    auto func_wrapper(T& arg)
    {
        func<T&>(arg);
    }
    
    #define func func_wrapper
    
    auto main() -> int
    {
        auto x = 5;
        func(x);
    
        auto& y = x;
        func(y);
    
        return 0;
    }
    

    预期输出(原文如此):

    T if ref: true
    T if ref: true
    

    【讨论】:

    • 如果你把它改成T&amp;&amp;,那么你的答案是正确的。
    • OP 指定了对“参考类型”的推导,我认为它是指左值参考。你认为他的意思是 r-value reference?
    • 好吧,我就是他。但不,你是对的。当我想传递引用时,我实际上想要一种 specify 的方法。我举了std::ref的例子,但是我不能采用std::reference_wrapper
    • 啊,我明白了。所以你需要某种带有代理对象的代理函数
    • 没错。但我想探索不必在对象中包装任何东西的可能性。这就是我提出强制模板扣除的原因。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-14
    • 1970-01-01
    • 1970-01-01
    • 2012-03-13
    • 2015-07-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多