-1

Requesting some help to understand the type deduction of rvalue reference. The non-templated version fails with the following error and I understand the reason.

error: cannot bind non-const lvalue reference of type 'const char*&' to an rvalue of type 'const char*'

With C++11, if I change the function void Firstfun(const Key& key) to void Firstfun(const Key&& key) then it compiles however the templated version works fine with lvalue reference parameter.

As for the templalted version, I thought compiler must have generated function with rvalue reference so checked it with __PRETTY_FUNCTION__ but didn't see it in the output of PRETTY_FUNCTION.

I did come across this discussion where @Anirban mentioned something on these lines.

For wrapper(A());, the type parameter T would still be deduced as A, and the parameter u would be of type A&&, called an rvalue reference to A.

So here are my questions:

  1. What is compiler doing with templated version to make it accept rvalue?
  2. The fix void Firstfun(const Key&& key) for non-templated version, is it valid and acceptable?

Non-templated version

#include <iostream>

namespace somens {

class Firstclass {
public:

    void Firstfun(const char*& key) {
        std::cout << __PRETTY_FUNCTION__ << '\n';
    }
};

class Secondclass {
    Firstclass f_class;

    char* create_buf(){
        char * buf = new char[10]; //buf will be freed elsewhere.
        return buf;
    }

public:
    void Secondfun (){
        f_class.Firstfun(create_buf());
    }

};
}

int main () {
  somens::Secondclass s_class;
  s_class.Secondfun();

}

Output from non-templated version

error: cannot bind non-const lvalue reference of type 'const char*&' to an rvalue of type 'const char*'

Templated version

#include <iostream>

namespace somens {
template<typename Key>
class Firstclass {
public:

    void Firstfun(const Key&  key) {
        std::cout << __PRETTY_FUNCTION__ << '\n';
    }
};

class Secondclass {
    Firstclass<const char*> f_class;

    char* create_buf(){
        char * buf = new char[10]; //buf will be freed elsewhere.
        return buf;
    }

public:
    void Secondfun (){
        f_class.Firstfun(create_buf());
    }

};
}

int main () {
  somens::Secondclass s_class;
  s_class.Secondfun();

}

Output from templated version

void somens::Firstclass::Firstfun(const Key&) [with Key = const char*]

1 Answers1

1

The key difference between your two snippets is that the first takes const char*&, and the second takes const Key& (aka Key const&), where Key is const char*.

Crucially, in the latter case, that gives you a const char* const& which (like any other lvalue reference to const) can bind to a temporary.

Remember, the const in const char* is irrelevant as that describes the pointee, not the pointer.

You didn't need templates. You could have observed this simply by writing using Key = const char*.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • Thanks for pointing out the proper location for const keyword. The pointer should have been const as that is what the reference is being created to. My understanding of the error was incorrect. Here is take 2 on it, please correct or confirm my understanding. The reason it fails is because of the implicit conversion of `b` from `char *` to `char const*` results in a rvalue which causes the error while assignment to the function parameter. – user2914100 Dec 25 '18 at 23:45
  • @user2914100 Hadn't even spotted that. That's true, but doesn't matter because `create_buf()` is regardless an rvalue anyway – Lightness Races in Orbit Dec 25 '18 at 23:46
  • you are right, I did not define `b` in my last comment. Suppose `char * b = create_buf(); f_class.Firstfun(b);` this will fail because of the implicit conversion from `char *` to `char const *`, I guess ... – user2914100 Dec 25 '18 at 23:53
  • @user2914100 I think so yeah :) – Lightness Races in Orbit Dec 26 '18 at 12:29