Perhaps this piece of code will illustrate my intent best:
#include <array>
template <size_t N>
void f(std::array<char, N> arr)
{
}
template <size_t N>
void f(std::array<char, N>&& arr)
{
static_assert(false, "This function may not be called with a temporary.");
}
f()
should compile for lvalues but not for rvalues. This code works with MSVC, but GCC trips on the static_assert
even though this overload is never called.
So my question is two-fold: how to express my intent properly with modern C++, and why does the compiler evaluate static_assert
in a "dead" template overload that's never instantiated?
Try it online: https://godbolt.org/z/yJJn7_
One option is to remove the static_assert
and instead mark the function as deleted. Then if you call it with an rvalue you will get an error saying you are trying to use a deleted function
template <size_t N>
void f(const std::array<char, N>& arr)
{
}
template <size_t N>
void f(const std::array<char, N>&& arr) = delete; // used const here just in case we get a const prvalue
int main()
{
std::array<char, 3> foo{};
f(foo);
//f(std::array<char, 3>{}); // error
return 0;
}
Simple enough.
template <size_t N>
void f(const std::array<char, N>&& arr) = delete;
It's possible using only a single function that takes a reference to a non-const object:
template<size_t N> void f(std::array<char, N>& arr);
No more overloads needed.
This rule is enforced by the language specification. However the Visual C++ compiler have an extension that allows rvalues to be passed to such a function.
An addition to other answers, I'd like to note that there is an example in the Standard library that corresponds exactly to what OP wants - std::addressof
:
template<class T>
constexpr T* addressof(T&) noexcept;
template<class T>
const T* addressof(const T&&) = delete;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.