2013-05-04 129 views
5

我想传递一个参数(一个或多个)(一些具体类型的,说int)由R-或左值(常数)参考成员函数。我的解决方案是:右值或左值(常数)参考参数

#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_referencestd::remove_const而不是std::decay的叠加,但这里只是简化。

+0

rvalue传递简单类型如'int'没有意义。在更一般的情况下,我相信C++ 11有一个特殊情况,其中右值参数将被读作右值或左值参数。尽管如此,我不记得确切的情况。 – Dave 2013-05-04 16:38:40

+0

所以你希望'x'是一个右值引用(如果通过右值引用)或左值引用给'const'?我是否正确理解,X &&不会被你接受,因为当左值被传递时,它将是对非''constst'的左值引用? – 2013-05-04 16:41:22

+0

嗯,我们走吧,我相信你正在努力做到这一点:http://thbecker.net/articles/rvalue_references/section_07.html这是在下一页使用rvalues解释。如果我误解了这个问题,大叫大叫。 – Dave 2013-05-04 16:41:40

回答

4

如果我正确理解你的问题,你希望有一个函数的参数是右值引用(如果提供右值)或左值引用const(在提供左值的情况下)。

但是会这个功能呢?那么,因为它必须能够处理这两种情况,包括提供左值的情况下,它不能修改它的输入(至少不是绑定到x参数的那个) - 如果是这样,它会违反语义const参考。

但话又说回来,如果它不能改变参数的状态,没有任何理由允许右值引用:宁可让x是左值参考const所有的时间。对const的左值引用可以绑定到右值,因此您将被允许传递右值和左值。

如果函数的语义是不同的依据是什么获得通过,那么我会说这更有意义,写这样的功能:一个接受一个右值引用,而另一种左值参考const

+0

constness是可选的(所有'&&','&','const'都允许) – Orient 2013-05-04 16:53:06

+1

@Dukales:我不明白:(你是什么意思?如果函数必须能够使用'const'这意味着它不会尝试修改'x'。但是,这意味着您不需要右值引用 – 2013-05-04 16:54:17

+0

您是否了解元编程?让我们假设,那些被传递参数的函数将决定如何处理(如何分配)它们的特定“参考性”和常量。 – Orient 2013-05-04 16:59:43

1

正如Andy所提到的,这里最重要的是你可以在你的函数内部这是有意义的。

  • 你可以把参数传递给另一个函数。在这种情况下,使用模板并不重要,因为如果给出了错误的参数类型,它仍然会产生编译错误(发送到第二个函数的错误类型)。您可以使用template <typename T> blah (T && x)
  • 还有什么需要你写取决于它是否是一个R-或1-参考值不同的代码,所以你需要这么写两个功能:blah (const int & x)blah (int && x)

我假设你必须尝试第一个选项,并试图使任何潜在的编译器错误更加用户友好。那么,我会说这不值得;程序员仍然会在任何像样的编译器输出中看到“被......调用”列表。

+0

在该函数下可以表示具有大量初始化列表的ctor。 – Orient 2013-05-04 17:07:17

+0

@Dukales:但这只是转发,所以你可以使用模板,如果错误地调用,仍然会出现编译错误。 – Dave 2013-05-04 17:09:29

1

其实,这是一个非常好的问题。到目前为止,我还一直在使用通用参考技巧加上enable_if锤子。在这里,我提出了一个不使用模板并使用左值转换作为替代方案的解决方案。

下面是其中的情况出现使用就地ofstream使用已知的例子是不可能的(或很难)在C++ 98的真实例子(我用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是因为可能你可以将一个转换为另一个!

std::ostringstream& operator<<(std::ostringstream&& oss, A const& a){ 
    return operator<<(oss, a); 
} 

这看起来像一个无限递归函数,但它不是因为oss是一个左值引用(是的,它是一个左值引用,因为它有一个名字)。所以它会调用其他的超载。

您仍然需要编写两个函数,但其​​中一个代码不需要维护。总之,如果“有意义”将函数同时应用于(非常量)左值引用和右值,这也意味着您可以将右值转换为左值并因此转发给单个函数。请注意,“它有意义”取决于上下文和预期代码的含义,而且我们必须通过明确地调用左值过载来“告知”编译器。

我并不是说这比使用通用参考更好,我认为它是一种替代方法,可以证明其意图更加清晰。

可编辑代码:http://ideone.com/XSxsvY。 (欢迎反馈)