Search code examples
c++visual-studio-2013operator-overloadingwindows-8.1function-call-operator

Passing a reference to template function call operator overload


I have a class which overloads the function call operator with a template function, like so:

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

I'd like to call it with a reference argument, however when trying to do so, it passes the argument as a value instead. Here's my test setup:

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;
}

The output is:

0110F738 -- Output of the address of 'i'

0110F664 -- Output of the address of the argument in the template overload

0110F738 -- Output of the address of the argument through 'test'

The template function 'test' is merely for validation.

The visual studio debugger confirms that it's using 'int' instead of 'int&' for the template overload:

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

How can I force it to use a reference instead? Is there a way to specify the types using <> on a template function call operator?


Solution

  • That's because in your case the cv-qualifiers and the reference-ness of the parameter are discarded when performing template type deduction. Pass via a std::ref wrapper instead

    t(std::ref(i));
    

    Simple example:

    #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
    }