在C++中,确定表达式是右值还是左值的最佳方法是什么?也许在实践中这并不有用,但因为我正在学习右值和左值,所以我认为编写一个名为 is_lvalue
的函数会很好,如果传入的表达式是左值,则返回true,否则返回false。
示例:
std::string a("Hello");
is_lvalue(std::string()); // false
is_lvalue(a); // true
template <typename T>
constexpr bool is_lvalue(T&&) {
return std::is_lvalue_reference<T>{};
}
std::string
左值,则T
将推断为std::string&
或const std::string&
,对于右值,它将推断为std::string
。请注意,Yakk的答案将返回不同类型,这允许更多的灵活性,您应该阅读该答案并可能使用它。我使用了两个重载的模板函数解决了上述问题。第一个函数以左值的引用作为输入,并返回true
。而第二个函数则使用右值引用。然后我让编译器根据输入的表达式来匹配正确的函数。
代码:
#include <iostream>
template <typename T>
constexpr bool is_lvalue(T&) {
return true;
}
template <typename T>
constexpr bool is_lvalue(T&&) {
return false;
}
int main()
{
std::string a = std::string("Hello");
std::cout << "Is lValue ? " << '\n';
std::cout << "std::string() : " << is_lvalue(std::string()) << '\n';
std::cout << "a : " << is_lvalue(a) << '\n';
std::cout << "a+b : " << is_lvalue(a+ std::string(" world!!! ")) << '\n';
}
输出:
Is Lvalue ?
std::string() : 0
a : 1
a+b : 0
我会借鉴boost::hana
的做法,使is_lvalue
的返回值将其参数的左值性编码为constexpr值和类型。
这使您可以进行标签分派而无需额外的模板代码。
template<class T>
constexpr std::is_lvalue_reference<T&&>
is_lvalue(T&&){return {};}
这个函数的主体并没有做任何事情,参数值也被忽略了。这使得即使在非常数表达式的情况下,它仍可以是constexpr。
使用这种技术的一个优点可以在这里看到:
void tag_dispatch( std::true_type ) {
std::cout << "true_type!\n";
}
void tag_dispatch( std::false_type ) {
std::cout << "not true, not true, shame on you\n";
}
tag_dispatch( is_lvalue( 3 ) );
is_lvalue
的返回值不仅在 constexpr
上下文中可用(因为 true_type
和 false_type
有一个 constexpr operator bool
),而且我们可以根据其状态轻松选择重载函数。
另一个优点是这使得编译器很难不内联结果。使用 constexpr
值,编译器可能会“轻松”忘记它是一个真正的常量;但对于类型,必须首先将其转换为 bool
才能有可能遗忘。
<T&&>
而不是<T>
? - Ryan Hainingis_lvalue_reference<Foo&&>
似乎比 is_lvalue_reference<Foo>
更清晰。 - Yakk - Adam Nevraumontstd::is_lvalue_reference
和 std::is_rvalue_reference
。std::string a("Hello");
std::is_lvalue_reference<decltype((std::string()))>::value; // false
std::is_lvalue_reference<decltype((a))>::value; // true
在C++17中,您将能够使用以下内容:
std::string a("Hello");
std::is_lvalue_reference_v<decltype((std::string()))>; // false
std::is_lvalue_reference_v<decltype((a))>; // true
或者你可以像@Ryan Haining建议的那样编写一个包装器,只需确保正确获取类型即可。
constexpr
,因为类型在编译时始终已知。 - Ryan Hainingstd::true_type
еТМfalse_type
дї•иОЈеЊЧжЫійЂШзЪДз°ЃеЃЪжАІгАВ - Yakk - Adam Nevraumontstd::true_type
的优点是什么? - Giuseppe Pes