我想通过r-或l-值(const)引用将参数(具体类型,比如int
)传递给成员函数。我的解决方案是:
#include <type_traits>
#include <utility>
struct F
{
using desired_parameter_type = int;
template< typename X, typename = typename std::enable_if< std::is_same< typename std::decay< X >::type, desired_parameter_type >::value >::type >
void operator () (X && x) const
{
// or even static_assert(std::is_same< typename std::decay< X >::type, desired_parameter_type >::value, "");
std::forward< X >(x); // something useful
}
};
另一个例子是http://pastebin.com/9kgHmsVC。
但它太冗长了。如何以更简单的方式做到这一点?
也许我应该使用std::remove_reference
和std::remove_const
而不是std::decay
的叠加,但这里只是简化。
答案 0 :(得分:4)
如果我理解你的问题,你希望有一个函数,其参数是一个右值引用(如果提供了右值)或左值引用const
(如果提供了左值)
但这个功能会做什么?好吧,因为它必须能够处理这两种情况,包括提供左值的情况,它不能修改它的输入(至少不是绑定到x
参数的那个) - 如果确实如此,它将违反const
引用的语义。
但是,如果它不能改变参数的状态,则没有理由允许rvalue引用:而是让x
始终是const
的左值引用。对const
的左值引用可以绑定到右值,因此您将被允许传递rvalues和左值。
如果函数的语义根据传递的内容而有所不同,那么我认为编写两个这样的函数更有意义:一个采用右值引用,另一个采用左值参考const
。
答案 1 :(得分:1)
正如Andy所提到的,重要的是你可以在你的函数中实际做这是有意义的。
template <typename T> blah (T && x)
。blah (const int & x)
和blah (int && x)
。< / LI>
我假设您必须尝试第一个选项,并且您尝试使任何潜在的编译器错误更加用户友好。好吧,我说这不值得;程序员仍会在任何体面的编译器的输出中看到“被...调用”列表。
答案 2 :(得分:1)
实际上,这是一个非常好的问题。到目前为止,我一直在使用通用参考技巧加上enable_if
锤子。在这里,我提出了一个不使用模板的解决方案,并使用左值投射作为替代方案。
以下是一个真实示例,其中使用C ++ 98中不可能(或非常难)使用的已知ofstream
用法示例出现情况(我在示例中使用ostringstream
使它更清楚)。
首先,您将看到一个关于左值引用的函数,如C ++ 98中常见的那样。
#include<iostream>
#include<sstream>
struct A{int impl_;};
std::ostringstream& operator<<(std::ostringstream& oss, A const& a){
oss << "A(" << a.impl_ << ")"; // possibly much longer code.
return oss;
}
// naive C++11 rvalue overload without using templates
std::ostringstream& operator<<(std::ostringstream&& oss, A const& a){
oss << "A(" << a.impl_ << ")"; // ok, but there is code repetition.
return oss;
}
int main() {
A a{2};
{// C++98 way
std::ostringstream oss;
oss << a;
std::cout << oss.str() << std::endl; // prints "A(2)", ok"
}
{// possible with C++11, because of the rvalue overload
std::cout << (std::ostringstream() << a).str() << std::endl; //prints "A(2)", ok
}
}
正如您在C ++ 11中所看到的,我们可以在C ++ 98中实现我们无法实现的功能。这是为了使用ostringstream
(或ofstream
)。 OP问题现在出现了,两个重载看起来非常相似,可以加在一起吗?
一种选择是使用通用引用(Ostream&&
),并可选择使用enable_if
来约束类型。不是很优雅。
我通过使用这个“真实世界”的例子发现,如果想为左值ref和rvalue引用相同的代码,因为可能你可以将一个转换为另一个!
std::ostringstream& operator<<(std::ostringstream&& oss, A const& a){
return operator<<(oss, a);
}
这看起来像一个无限递归函数,但它不是因为oss
是一个左值引用(是的,它是一个左值引用,因为它有一个名称)。所以它会调用另一个重载。
您仍然需要编写两个函数,但其中一个函数具有您无需维护的代码。
总之,如果“有意义”©将函数应用于(非常量)左值引用和右值,这也意味着您可以将右值转换为左值,因此转发到单个函数。请注意,“它有意义”取决于上下文和预期代码的含义,并且我们必须通过明确地调用左值超载来“告诉”编译器。
我并不是说这比使用通用引用更好,我说它是一种替代方案,可以说意图更明确。
此处可编辑代码:http://ideone.com/XSxsvY。 (欢迎反馈)