以在使用临时对象调用时生成编译器错误的方式重载方法
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
?
可以只使用一个引用非常量对象的函数:
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;
也许这段代码最能说明我的意图:
#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
?
可以只使用一个引用非常量对象的函数:
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;