重载方法的方式会在使用临时调用时生成编译器错误

Overload a method in a way that generates a compiler error when called with a temporary

本文关键字:调用 错误 编译器 方法 方式会 重载      更新时间:2023-10-16

也许这段代码最能说明我的意图:

#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()应该为左值而不是为右值编译。此代码适用于MSVC,但GCC在static_assert上跳闸,即使从未调用此重载。

因此,我的问题有两个:如何用现代C++正确地表达我的意图,以及为什么编译器在从未实例化的"死"模板重载中评估static_assert

在线试用:https://godbolt.org/z/yJJn7_

一个选项是删除static_assert,而将函数标记为已删除。然后,如果你用右值调用它,你会得到一个错误,说你试图使用一个已删除的函数

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;
}

足够简单。

template <size_t N>
void f(const std::array<char, N>&& arr) = delete;

只使用一个引用非常量对象的函数是可能的:

template<size_t N> void f(std::array<char, N>& arr);

不再需要过载。

此规则由语言规范强制执行但是Visual C++编译器有一个扩展,允许将右值传递给这样的函数。

除了其他答案之外,我想注意的是,标准库中有一个示例与OP想要的完全对应-std::addressof:

template<class T>
constexpr T* addressof(T&) noexcept;
template<class T>
const T* addressof(const T&&) = delete;