如何以编程方式确定在C ++中expression式是右值还是左值?
在C ++中确定expression式是右值还是左值的最好方法是什么? 也许,这在实践中是没有用的,但是因为我正在学习右值和左值,所以我认为有一个函数is_lvalue
将返回true,如果在input中传递的expression式是左值,否则返回false。
例:
std::string a("Hello"); is_lvalue(std::string()); // false is_lvalue(a); // true
大部分的工作已经由stdlib完成了,你只需要一个函数包装器:
template <typename T> constexpr bool is_lvalue(T&&) { return std::is_lvalue_reference<T>{}; }
在你通过一个std::string
左值的情况下,那么T
会推导出std::string&
或const std::string&
,对于rvalues它会推导出std::string
我用两个重载的模板函数解决了上述问题。 第一个input一个左值的引用并返回true
。 而第二个函数使用右值的引用。 然后,我让编译器根据作为input传递的expression式匹配正确的函数。
码:
#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
值和一个types进行编码。
这可以让你做的东西,如标签调度没有额外的样板。
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
的返回值在constexpr
上下文中可用(因为true_type
和false_type
有一个constexpr operator bool
),但是我们可以根据其状态轻松地select一个超载。
另一个好处是编译器难以内联结果。 有了constexpr
值,编译器可以很容易的忘记它是一个真正的常量。 与一个types,它必须首先转换为bool
可能性被遗忘发生。
使用std::is_lvalue_reference
和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海宁build议的包装,只要确保你的types正确。