【问题标题】:Passing a reference to template function call operator overload传递对模板函数调用运算符重载的引用
【发布时间】:2015-05-22 17:54:08
【问题描述】:

我有一个类,它使用模板函数重载函数调用运算符,如下所示:

class Test
{
public:
    template<class T>
        void operator()(T t)
    {
        std::cout<<(&t)<<std::endl;
    };
};

我想用引用参数调用它,但是当尝试这样做时,它会将参数作为值传递。这是我的测试设置:

template<class T>
    void test(T t) {std::cout<<(&t)<<std::endl;}

int main(int argc,char *argv[])
{
    Test t;
    int i = 5;
    std::cout<<(&i)<<std::endl;
    t((int&)i); // Passes the argument as a value/copy?
    test<int&>(i); // Passes the argument as a reference
    while(true);
    return 0;
}

输出是:

0110F738 -- 'i' 的地址输出

0110F664 -- 模板重载中参数地址的输出

0110F738 -- 通过'test'输出参数的地址

模板函数“test”仅用于验证。

Visual Studio 调试器确认它使用 'int' 而不是 'int&' 来进行模板重载:

test_function_call.exe!Test::operator()(int t) 第 9 行 C++

我怎样才能强制它使用引用呢?有没有办法在模板函数调用运算符上使用 来指定类型?

【问题讨论】:

  • 你想要void operator()(cont T&amp; t)
  • 我不希望它是'const',我仍然需要能够修改值。

标签: c++ visual-studio-2013 operator-overloading windows-8.1 function-call-operator


【解决方案1】:

这是因为在您的情况下,执行模板类型推导时会丢弃参数的 cv 限定符和引用性。而是通过 std::ref 包装器传递

t(std::ref(i));

简单示例:

#include <iostream>
#include <functional>

template<typename T>
void f(T param)
{
    ++param;
}

int main()
{
    int i = 0;
    f(std::ref(i));
    std::cout << i << std::endl; // i is modified here, displays 1
}

【讨论】:

  • 不知道 std::ref,但是行为没有改变,它仍然将其作为值传递。
  • @Silverlan 你怎么知道?如果您例如,它将“模拟”通过引用传递在operator() 中修改t。在里面做++t之类的操作,你会看到i会被修改。
  • 那个模拟不是真实的——有很多方法可以区分T&amp;std::reference_wrapper&lt;T&gt;
  • 你说得对,它确实有效。但是为什么它仍然在 operator() 中为我提供了一个不同的地址?
  • @Puppy 确实,我想不出更好的措辞 ;)
【解决方案2】:

您可以使用通用参考:

class Test
{
public:
    template<class T>
    void operator()(T&& t)
    {
        std::cout<<(&t)<<std::endl;
    };
};

【讨论】:

  • 我还能用这种方式将它作为值/副本传递吗?我也希望能够做到。
  • @Silverlan 不是真的,t 的类型将被推断为T&amp;T,在reference collapsing 之后变为T&amp;T&amp;&amp;
猜你喜欢
  • 1970-01-01
  • 2014-07-24
  • 1970-01-01
  • 2016-06-10
  • 2019-03-03
  • 2020-10-15
  • 2021-10-09
  • 2015-05-08
相关资源
最近更新 更多