web-dev-qa-db-ja.com

C ++で式が右辺値または左辺値であるかどうかをプログラムで判断する方法

式がC++の右辺値または左辺値であるかどうかを判断する最良の方法は何ですか?おそらく、これは実際には有用ではありませんが、右辺値と左辺値を学習しているので、関数is_lvalueは、入力で渡された式が左辺値である場合はtrueを返し、そうでない場合はfalseを返します。

例:

std::string a("Hello");
is_lvalue(std::string()); // false
is_lvalue(a); // true  
49
Giuseppe Pes

ほとんどの作業はすでにstdlibによって行われています。関数ラッパーが必要です。

template <typename T>
constexpr bool is_lvalue(T&&) {
  return std::is_lvalue_reference<T>{};
}

std::string lvalueを渡す場合、Tstd::string&またはconst std::string&に推定され、右辺値の場合はstd::stringに推定されます

Yakk's answer は異なる型を返すことに注意してください。これにより柔軟性が増し、その答えを読んで、おそらく代わりに使用する必要があります。

59
Ryan Haining

2つのオーバーロードされたテンプレート関数を使用して、上記の質問を解決しました。最初は、入力として左辺値への参照を取り、trueを返します。一方、2番目の関数は右辺値への参照を使用します。次に、入力として渡された式に応じて、コンパイラに正しい関数を一致させます。

コード:

#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
26
Giuseppe Pes

boost::hanaからページを取得し、is_lvalueの戻り値にその引数の左辺値をエンコードさせますbothとしてconstexpr値、- andタイプとして。

これにより、余分なボイラープレートなしでタグのディスパッチなどを行うことができます。

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があるため)、簡単に選択できますその状態に基づいて過負荷。

もう1つの利点は、コンパイラが結果をnotインライン化するのを難しくすることです。 constexpr値を使用すると、コンパイラはそれが真の定数であることを「簡単に」忘れることができます。型がある場合、忘れられる可能性があるため、最初に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 Hainingが提案するようにラッパーを書くこともできます。タイプが正しいことを確認してください。

8
Pharap