繁体   English   中英

C++ - 使用模板传递引用/值

[英]C++ - Pass by Reference/ Value using templates

语境

or .向函数传递参数时,我们可以

通过引用传递的一个优点是参数不需要通过自身的副本来实现,这对于包含大量数据的自定义对象似乎是有利的。

但是对于多个类接口,为每个接口创建一个传递引用函数可能......不整洁,例如:

void parse(Console&);
void parse(Dialog&);
void parse(Image&);
void parse(Window&);
void parse(...); // how many more overloads?!

那么,使用模板来解决这个凌乱的问题,对吗?

template <typename type> void parse(type&);

但我遇到了一个颠簸......


尝试的解决方案(代码)

#include <iostream>

class Object { public:
    // Copy/ Move constructors implicitly defined;
    //   Same goes for the assignment operator.
    constexpr inline Object(void) {}

    // Test if the object can be a reference or is an expression value.
    template <typename type>
    inline static void parse(type) noexcept { std::cout << "[pass-by-value]" << std::endl; }

    template <typename type>
    inline static void parse(type&) noexcept { std::cout << "[pass-by-reference]" << std::endl; }
};

按值传递对象有效

Object::parse(Object()); // SUCCESS: "pass-by-value"

但是使用引用会导致测试函数与其重载发生冲突。

Object object {};
Object::parse(object); // ERROR: Ambiguous call of `Object::parse` function.
                       // EXPECTED: "pass-by-reference"

我认为这个电话是模棱两可的,因为
parse(type)重载用{type=Object&}
parse(type&)重载用{type=Object}初始化。

虽然,我认为parse(type&)重载会是首选,但显然情况并非如此。

那么,我在这里错过了什么?


我们如何区分可能是引用的参数或使用模板函数的常量表达式的参数?

Image() [type=Image] Image() [type=Image]

Image image; // -> image [type=Image&]
Image images[1]; // -> images[0] [type=Image&]
Image *image_p; // -> *(image_p + 0) [type=Image&]

根据您的评论,您似乎想要的是对 r 值引用的重载(以便您可以区分何时传递了临时对象或何时传递了现有对象)

void foo(int& x){
    std::cout << x << " was an l-value\n";
}

void foo(int&& x){
    std::cout << x << " was an r-value (possibly a temporary or std::move result)\n";
}

int main(){
    int x = 5;
    foo(x);
    foo(10);
}

请注意,第二个版本也不执行复制。 构造一个临时对象,然后使用移动语义。


如果您不想修改原始对象并且不关心区别,您可以简单地将参数设为const引用

void foo(const int& x){
    std::cout << x << " may or may not have been a temporary "
                      "(it's lifetime is prolonged until end of this function)\n";
}


int main(){
    int x = 5;
    foo(x);
    foo(10);
}

这里也不需要副本。

这是一个比较常见的问题。

您可以根据对象的大小以及它是否可以简单地复制来定义方法。 如果它不是简单的可复制或太大,请使用 const 引用 - 否则使用复制。

这样您就没有歧义要解决 - 只需利用 SFINEA 启用/禁用某些功能。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM