如何以编程方式确定在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_typefalse_type有一个constexpr operator bool ),但是我们可以根据其状态轻松地select一个超载。

另一个好处是编译器难以内联结果。 有了constexpr值,编译器可以很容易的忘记它是一个真正的常量。 与一个types,它必须首先转换为bool可能性被遗忘发生。

使用std::is_lvalue_referencestd::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正确。