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

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

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

#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++ 正确表达我的意图,以及为什么编译器在从未实例化的 "dead" 模板重载中评估 static_assert

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

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

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

不再需要重载。

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

很简单。

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

一个选项是删除 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;
}

除其他答案外,我想指出标准库中有一个示例完全符合 OP 的要求 - std::addressof:

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

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