首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >重载,具有r值参考,类模板的构造函数

重载,具有r值参考,类模板的构造函数
EN

Stack Overflow用户
提问于 2014-07-15 10:10:02
回答 2查看 392关注 0票数 1

虽然最初似乎是工作中,但当通过maker函数调用时(为了进行模板参数推导),存在两个重载,一个用于T const&,另一个用于T&& 断点编译

代码语言:javascript
复制
#include <iostream>
#include <utility>
#include <functional>

using namespace std;

// -----------------------------------------------
template<typename T, typename F>
struct Test
{
    T m_resource;
    F m_deleter; 

    Test(T&& resource, F&& deleter) 
    : m_resource(move(resource)), m_deleter(move(deleter))
    {
    }
    Test(T const& resource, F const& deleter) 
    : m_resource(resource), m_deleter(deleter)
    {
    }
};
// -----------------------------------------------

// -----------------------------------------------
template<typename T, typename F>
Test<T, F> test(T&& t, F&& f)
{
    return Test<T, F>(move(t), move(f));
}
template<typename T, typename F>
Test<T, F> test(T const& t, F const& f)
{
    return Test<T, F>(t, f);
}
// -----------------------------------------------

int main() 
{
    // construct from temporaries --------------------
    Test<int*, function<void(int*)>> t(new int, [](int *k) {}); // OK - constructor
    auto tm = test(new int, [](int *k){});                      // OK - maker function
    // -----------------------------------------------

    // construct from l-values -----------------------
    int *N = new int(24);
    auto F = function<void(int*)>([](int *k){});

    Test<int*, function<void(int*)>> tt(N, F); // OK    - construction
    auto m = test(N, F);                       // Error - maker function
    // -----------------------------------------------

    return 0;
}

有什么想法吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-07-15 10:36:32

代码语言:javascript
复制
template<typename T, typename F>
Test<T, F> test(T&& t, F&& f)
{
    return Test<T, F>(move(t), move(f));
}

此函数模板有两个参数,它们是通用引用。表单模板类型参数&&的函数模板参数遵循特殊的推导规则:如果参数是lvalue,则模板类型参数被推导为lvalue引用类型。如果参数是rvalue,则推导的类型不是引用。

代码语言:javascript
复制
auto m = test(N, F);

int* Nfunction<void(int*)> F是L值,因此对于上述函数模板,T推导为int*&F推导为function<void(int*)>&。引用折叠应用,参数T&&变为int*& &&,并折叠为int*& (与F&&类似)。

因此,类模板是用引用类型(T == int*&F == function<void(int*)>&)实例化的。在类模板中,

代码语言:javascript
复制
Test(T&& resource, F&& deleter)
Test(T const& resource, F const& deleter) 

将产生相同的签名,因为int*& &&int*& const&都折叠为int*&,对于F也是如此。

注意,当参数不是const时,参数int*&的函数比参数int* const&的函数更可取。因此,函数模板

代码语言:javascript
复制
template<typename T, typename F>
Test<T, F> test(T const& t, F const& f)

将不会在出现错误的行中使用。一般说来,通用的参考参数是非常贪婪的。

典型的解决方案是使用乔纳森·韦克利回答中描述的完美转发。

票数 6
EN

Stack Overflow用户

发布于 2014-07-15 10:33:15

代码语言:javascript
复制
template<typename T, typename F>
Test<T, F> test(T&& t, F&& f)
{
    return Test<T, F>(move(t), move(f));
}

此函数处理lvalue和rvalue。当您调用test(N, F)时,参数是非const l值,因此使用了上面的重载,而不是 test(const T&, const F&) 1。它将类模板实例化为Test<int*&, std::function<void(int*)>&>,这不是您想要的。

您只需要一个maker函数:

代码语言:javascript
复制
template<typename T, typename F>
auto test(T&& t, F&& f)
-> Test<typename std::decay<T>::type, typename std::decay<F>::type>
{
    return { std::forward<T>(t), std::forward<F>(f) };
}

这将接受任何lvalue和rvalue的组合,它将确保您返回所需的类型,并且它将使用它们的原始值类别完美地将参数转发给Test构造函数。

你应该读/看C++11中的通用引用

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24755451

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档