Function that can receive any of T, T&, and T&& as input, AND also recognize its type?

huangapple go评论122阅读模式
英文:

Function that can receive any of T, T&, and T&& as input, AND also recognize its type?

问题

以下是翻译好的代码部分:

template<class T> void test(T&& t){
    if constexpr(std::is_same_v<T, int>){
        std::cout<< "= int"<<std::endl;
    }
    if constexpr(std::is_same_v<T, const int&>){
        std::cout<< "= const int&"<<std::endl;
    }
    if constexpr(std::is_same_v<T, int&>){
        std::cout<< "= int&"<<std::endl;
    }
    if constexpr(std::is_same_v<T, int&&>){
        std::cout<< "= int&&"<<std::endl;
    }
    if constexpr(std::is_same_v<T, std::nullptr_t>){
        std::cout<< "= std::nullptr_t"<<std::endl;
    }
}

int funcReturnInt(){return 5;}
    
int main(){
    const int a=0;
    test(funcReturnInt()); // int  (correct)
    test(a);        // const int&   (correct)
    test(nullptr);  // std::nullptr_t  (correct)
    int s=0;
    test(std::move(s)); // print "int" (not "int&&") , I am sad
}

希望这对你有所帮助。

英文:

I want to create a function that correctly recognizes the type of its parameter.

template&lt;class T&gt; void test(T&amp;&amp; t){
    if constexpr(std::is_same_v&lt;T,int&gt;){
        std::cout&lt;&lt; &quot;= int&quot;&lt;&lt;std::endl;
    }
    if constexpr(std::is_same_v&lt;T,const int&amp;&gt;){
        std::cout&lt;&lt; &quot;= const int&amp;&quot;&lt;&lt;std::endl;
    }
    if constexpr(std::is_same_v&lt;T,int&amp;&gt;){
        std::cout&lt;&lt; &quot;= int&amp;&quot;&lt;&lt;std::endl;
    }
    if constexpr(std::is_same_v&lt;T,int&amp;&amp;&gt;){
        std::cout&lt;&lt; &quot;= int&amp;&amp;&quot;&lt;&lt;std::endl;
    }
    if constexpr(std::is_same_v&lt;T,std::nullptr_t&gt;){
        std::cout&lt;&lt; &quot;= std::nullptr_t&quot;&lt;&lt;std::endl;
    }
}

int funcReturnInt(){return 5;}
    
int main(){
    const int a=0;
    test(funcReturnInt()); // int  (correct)
    test(a);        // const int&amp;   (correct)
    test(nullptr);  // std::nullptr_t  (correct)
    int s=0;
    test(std::move(s)); // print &quot;int&quot; (not &quot;int&amp;&amp;&quot;) , I am sad
}

How to create the test() function so it can recognize the type of its single parameter correctly in every case?

I am new to T&amp;&amp;, so I have read some guides about rvalue references (1, 2, 3), but they don't describe how to create such a full-awareness wildcard function like test&lt;T&gt;(T??).

I will apply the solution as test() requires ... {} later.

I prefer to avoid overloading, because I love to make the code compact in 1 place (for educational purpose, too).

Edit :: Very useful comments state that it is generally not possible. Why does my code check other cases correctly, but C++ takes a liberty to get rid of my &amp;&amp;? Please post it as a solution.

I still doubt why int&amp; in main() becomes T=int&amp; correctly but int&amp;&amp; in main() becomes T=int.

答案1

得分: 2

  • 我是新手,所以我阅读了一些关于 rvalue references(1, 2, 3)的指南,但它们没有描述如何创建一个完全意识到的通配符函数,比如 test<T>(T??)

  • 在这个声明中:

    template<class T> void test(T&& t)
    

    尽管常常被误认为是一个,但 t 不是一个右值引用,它是转发引用(有时称为通用引用)。要理解转发引用,我们需要了解更多关于右值引用的内容,例如 引用折叠 规则和完美转发。详情请参见以下问答:

  • 我仍然怀疑为什么 main() 中的 int& 变成了 T=int&,但 main() 中的 int&& 变成了 T=int

  • 在调用中:

    test(std::move(s));
    

    参数类型 A 是 int&&,完整的参数类型是 int&&,这意味着推断出的 Tint

    test<int>(int&& t);
    

    参考详情,请参见 [temp.deduct.call]/3

  • 通用引用在参数类型是左值时特别适用于引用折叠规则。对于调用 test(a),参数类型是 int const,但为了推断的目的,将 int const& 用于推断 Tint const&,其中生成的函数参数类型 T&&int const&& && 折叠为 int const&&& & -> &)。

英文:

Emphasis mine:

> I am new to T&amp;&amp;, so I have read some guides about rvalue references (1, 2, 3), but they don't describe how to create such a full-awareness wildcard function like test&lt;T&gt;(T??).

In this declaration:

> template<class T> void test(T&& t)

whilst commonly mistaken for one, t is not an rvalue reference, it is forwarding reference (sometimes referred to as universal references). To understand forwarding references we need to understand more than rvalue references, e.g. reference collapsing rules and perfect forwarding. See e.g. the following Q&A for details:

> I still doubt why int&amp; in main() becomes T=int&amp; correctly but int&amp;&amp; in main() becomes `T=int.

In the call

> test(std::move(s));

the argument type A is int&amp;&amp;, the complete parameter type is int&amp;&amp; meaning the deduced T is int

test&lt;int&gt;(int&amp;&amp; t);
     ^^^  ^^^^^ parameter-type (T&amp;&amp; -&gt; int&amp;&amp;)
       \ deduced T

Refer to e.g. [temp.deduct.call]/3 for details.

Universal references particularly apply reference collapsing rules when the argument type is an lvalue. For the call test(a) the argument type is int const, but for purposes of deduction, int const&amp; is used in place, deducing T to int const&amp;, where the resulting function parameter type T&amp;&amp; is collapsed from int const&amp; &amp;&amp; to int const&amp; (&amp;&amp; &amp; -> &amp;).

huangapple
  • 本文由 发表于 2023年8月10日 15:09:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76873361.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定