如何以编程方式确定表达式在 C++ 中是右值还是左值?
How to determine programmatically if an expression is rvalue or lvalue in C++?
在 C++ 中确定表达式是右值还是左值的最佳方法是什么?可能这在实践中没有用,但是因为我正在学习右值和左值,所以我认为如果输入中传递的表达式是左值则为 returns true 的函数 is_lvalue
会很好,否则为 false .
示例:
std::string a("Hello");
is_lvalue(std::string()); // false
is_lvalue(a); // true
我用两个重载的模板函数解决了上面的问题。第一个将对左值和 return 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
stdlib 已经为您完成了大部分工作,您只需要一个函数包装器:
template <typename T>
constexpr bool is_lvalue(T&&) {
return std::is_lvalue_reference<T>{};
}
在你传递 std::string
左值的情况下,T
将推导为 std::string&
或 const std::string&
,对于右值,它将推导为 std::string
请注意 将 return 另一种类型,这样可以提供更大的灵活性,您应该阅读该答案并可能改用它。
使用std::is_lvalue_reference
and std::is_rvalue_reference
.
如果您喜欢使用 decltype,则不需要包装器。
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 的建议编写一个包装器,只要确保您的类型正确即可。
我将从 boost::hana
中获取一页,并使 is_lvalue
的 return 值编码其参数的左值 both作为 constexpr
值, 和 作为类型。
这让您无需额外的样板即可执行标签分派等操作。
template<class T>
constexpr std::is_lvalue_reference<T&&>
is_lvalue(T&&){return {};}
这个函数的主体什么都不做,参数的值被忽略。这让它即使在非 constexpr 值上也是 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
的 return 值在 constexpr
上下文中可用(因为 true_type
和 false_type
具有 constexpr operator bool
), 但我们可以根据其状态轻松选择重载。
另一个优点是编译器很难不内联结果。使用 constexpr
值,编译器可以 'easily' 忘记它是一个真正的常量;对于类型,必须先将其转换为 bool
,否则可能会被遗忘。
在 C++ 中确定表达式是右值还是左值的最佳方法是什么?可能这在实践中没有用,但是因为我正在学习右值和左值,所以我认为如果输入中传递的表达式是左值则为 returns true 的函数 is_lvalue
会很好,否则为 false .
示例:
std::string a("Hello");
is_lvalue(std::string()); // false
is_lvalue(a); // true
我用两个重载的模板函数解决了上面的问题。第一个将对左值和 return 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
stdlib 已经为您完成了大部分工作,您只需要一个函数包装器:
template <typename T>
constexpr bool is_lvalue(T&&) {
return std::is_lvalue_reference<T>{};
}
在你传递 std::string
左值的情况下,T
将推导为 std::string&
或 const std::string&
,对于右值,它将推导为 std::string
请注意
使用std::is_lvalue_reference
and std::is_rvalue_reference
.
如果您喜欢使用 decltype,则不需要包装器。
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 的建议编写一个包装器,只要确保您的类型正确即可。
我将从 boost::hana
中获取一页,并使 is_lvalue
的 return 值编码其参数的左值 both作为 constexpr
值, 和 作为类型。
这让您无需额外的样板即可执行标签分派等操作。
template<class T>
constexpr std::is_lvalue_reference<T&&>
is_lvalue(T&&){return {};}
这个函数的主体什么都不做,参数的值被忽略。这让它即使在非 constexpr 值上也是 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
的 return 值在 constexpr
上下文中可用(因为 true_type
和 false_type
具有 constexpr operator bool
), 但我们可以根据其状态轻松选择重载。
另一个优点是编译器很难不内联结果。使用 constexpr
值,编译器可以 'easily' 忘记它是一个真正的常量;对于类型,必须先将其转换为 bool
,否则可能会被遗忘。