Mordachai
Mordachai

Reputation: 9642

How to write const ref without allowing temporary creation

I want to be able to supply functions which take an existing object of a given type by const reference.

i.e. I want by-const-ref-but-no-temporaries-created. [edited this phrase to clarify it!]

I can't think of any way to express that in C++ directly:

1 void fn(const T & t)
will create a temporary T from an S if a (non-explicit) T(S) exists.

2 void fn(T & t)
will only allow a non-const t as an argument (I need this to work for const t's as well).

3 void fn(T && t)
requires a non-const rvalue.

4 void fn(const T && t)
requires a const rvalue

Is there any way to do this - accept any argument by reference, const, without allowing a temp to be created?


Failed thoughts:

Supplying #2 and #4 without supply the other two, and now we have an unambiguous fn that takes a reference to any existing T (but won't silently generate a temporary)?

Nope, that isn't adequate either, because I need to also be able to bind to a const T & - Where the target object is itself been passed in by const reference to our caller...


I guess I see no way to achieve this except in the case where I can control T to ensure it doesn't supply an implicit T(S).

Am I right, or am I overlooking some solution?

Upvotes: 2

Views: 111

Answers (2)

Nir Friedman
Nir Friedman

Reputation: 17704

Judging from the comments, it seems like your actual question has nothing to do with rvalues and lvalues, but simply preventing implicit conversions. You can do this by changing the function to a function template, and then constraining the template with sfinae:

template <class T, std::enable_if_t<std::is_same<std::decay_t<T>, CString>::value, int> = 0>
void fn(const T&) {

}

This will only work if called with some kind of CString, a type that implicit converts to a CString will not work.

Live example: http://coliru.stacked-crooked.com/a/80602c39cdc4d35e

That said, a better solution would simply be to change those functions to accept a string_view, which can be cheaply implicitly constructed from various kinds of strings. I don't know if it handles CString or not, but you can always right your own. It's a fairly simple class to write. http://en.cppreference.com/w/cpp/string/basic_string_view

Upvotes: 3

NathanOliver
NathanOliver

Reputation: 180500

If this is a free function then you can do as nwp suggests and add an overload taking a rvalue reference and deleting it.

void fn(const SomeType& t)
{
    // stuff to do with const lvalue
}

void fn(SomeType&&) = delete; // compiler error if you give me an rvalue

This works because a rvalue reference is preferred over a reference to const. So when overload resolution kicks in and you pass a temporary the compiler will select void fn(const T&&) as the best match. After that it will see that the function is deleted and it will issue a compiler error

Upvotes: 3

Related Questions