Deny passing a rvalue reference to a function

We have the following convenience function that retrieves a value from the map or returns the default return value if the key is not found.

template <class Collection> const typename Collection::value_type::second_type& FindWithDefault(const Collection& collection, const typename Collection::value_type::first_type& key, const typename Collection::value_type::second_type& value) { typename Collection::const_iterator it = collection.find(key); if (it == collection.end()) { return value; } return it->second; } 

The problem with this function is that it allows you to pass a temporary object as the third argument, which would be an error. For instance:

 const string& foo = FindWithDefault(my_map, ""); 

Is there any way to prevent the passing of rvalue references to the third argument using std :: is_rvalue_reference and static assert?

+5
source share
1 answer

Adding this extra overload should work (unchecked):

 template <class Collection> const typename Collection::value_type::second_type& FindWithDefault(const Collection& collection, const typename Collection::value_type::first_type& key, const typename Collection::value_type::second_type&& value) = delete; 

Overload resolution will select this overload for rvalue references, and = delete will make it a compile-time error. Alternatively, if you want to specify a custom message, you can go to

 template <class Collection> const typename Collection::value_type::second_type& FindWithDefault(const Collection& collection, const typename Collection::value_type::first_type& key, const typename Collection::value_type::second_type&& value) { static_assert( !std::is_same<Collection, Collection>::value, // always false "No rvalue references allowed!"); } 

std::is_same is to make static_assert dependent on the template parameter, otherwise it will cause a compilation error even when the overload is not called.

EDIT: Here is a minimal complete example:

 void foo(char const&) { }; void foo(char const&&) = delete; int main() { char c = 'c'; foo(c); // OK foo('x'); // Compiler error } 

MSVC gives the following error for the second call to foo :

 rval.cpp(8) : error C2280: 'void foo(const char &&)' : attempting to reference a deleted function rval.cpp(2): See declaration of 'foo' 

The first call, however, works fine, and if you comment out the second, the program compiles.

+6
source

Source: https://habr.com/ru/post/1214232/


All Articles