完美转发混乱

问题描述 投票:0回答:2

大家好

template<typename X>
int mycall(const X& a)
{
    std::cout << ">>>  " << "int mycall(const X& a)" << std::endl;
    return 0;
}

template<typename X>
int mycall(X&& a)
{
    std::cout << ">>>  " << "int mycall(X&& a)" << std::endl;
    return 0;
}



template <typename T>
class CClass
{
public:

    CClass(T t) : m_t{t}
    {
    }

    template<typename U>
    auto operator()(U&& t)
    {
        mycall(std::forward<U>(t));
    }


private:

    T m_t;
};



class A{};

int main()
{

    CClass cc{5};

    //1..
    int x = 9;    
    cc(x);
    
    cc(10);
    cc(A{});

    //4..
    A a{};
    cc(a);

    return 0;
}

output:

>>>  int mycall(X&& a)
>>>  int mycall(X&& a)
>>>  int mycall(X&& a)
>>>  int mycall(X&& a)

在上面的示例中,对于 firstfourth 调用,我最初预计通用引用会推导为左值引用,导致由于完美转发而调用 mycall(const T&) 版本。但是,我观察到调用了 mycall(T&&) 版本。

当我删除 const 限定符,将函数更改为 mycall(T&) 时,第一个和第四个调用将作为左值引用转发,因此,mycall(T&) 版本将按预期调用。这里的const限定符有什么作用呢?为什么参数作为右值引用转发?

c++ perfect-forwarding
2个回答
0
投票

正如评论中提到的,

int mycall(X&& a)
也使用转发引用,因此它比其他模板更受青睐。

转发需要推导模板参数,因此获得所需输出的一种方法是不让它再次推导:

template<typename U>
auto operator()(U&& t)
{
    mycall<U>(std::forward<U>(t));
}

结果输出:

>>>  int mycall(const X& a)
>>>  int mycall(X&& a)
>>>  int mycall(X&& a)
>>>  int mycall(const X& a)

0
投票

感谢您的评论。我已将此代码修改如下

int mycall(const int& a)
{
    std::cout << ">>>  " << "int mycall(const int& a)" << std::endl;
    return 0;
}


int mycall(int&& a)
{
    std::cout << ">>>  " << "int mycall(int&& a)" << std::endl;
    return 0;
}


template <typename T>
class CountClass
{
public:

    CountClass(T function) : m_function{function}
    {
    }

    template<typename ...Args>
    auto operator()(Args... args)
    {
        m_count++;
        return mycall(std::forward<Args>(args)...);
    }

    int get_call_count() const
    {
        return m_count;
    }

private:

    T m_function;
    int m_count{};
};



int main()
{
    auto l = [](int p1, int p2){ std:cout << "calling lambda..." << p1 + p2 << std::endl; };
    CountClass<decltype(l)> cc{l};

    int x = 9;
    cc(x);

    cc(10);
    
    std::cout << ">>> " << cc.get_call_count() << std::endl;

    return 0;
}

这次目标函数没有任何通用引用。但结果是一样的。

>>>  int mycall(int&& a)
>>>  int mycall(int&& a)

你有什么想法吗?谢谢。

© www.soinside.com 2019 - 2024. All rights reserved.