大家好
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)
在上面的示例中,对于 first 和 fourth 调用,我最初预计通用引用会推导为左值引用,导致由于完美转发而调用 mycall(const T&) 版本。但是,我观察到调用了 mycall(T&&) 版本。
当我删除 const 限定符,将函数更改为 mycall(T&) 时,第一个和第四个调用将作为左值引用转发,因此,mycall(T&) 版本将按预期调用。这里的const限定符有什么作用呢?为什么参数作为右值引用转发?
正如评论中提到的,
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)
感谢您的评论。我已将此代码修改如下
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)
你有什么想法吗?谢谢。