Reputation: 1513
We have the following convenience function that fetches a value from a map or returns a fallback default value if key 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 passing a temporary object as third argument which would be a bug. For example:
const string& foo = FindWithDefault(my_map, "");
Is it possible to disallow passing rvalue references to the third argument in some way by using std::is_rvalue_reference and static assert?
Upvotes: 11
Views: 2532
Reputation: 3249
Adding this additional overload should work (untested):
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 the = delete
makes it a compile time error. Alternatively, if you want to specify a custom message, you could go for
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!");
}
The std::is_same
is there to make the static_assert
dependent on the template parameter, otherwise it would 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 here 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 then the program compiles.
Upvotes: 11