2017-03-27 7 views
1
#include <type_traits> 

#define FORWARD(arg)\ 
std::forward<decltype(arg)>(arg) 

template<typename... Args> 
constexpr bool AndL(Args&&... args) 
{ 
    return (... && FORWARD(args)); 
} 

template<typename... Args> 
constexpr bool AndR(Args&&... args) 
{ 
    return (FORWARD(args) && ...); 
} 

int main() 
{ 
    bool* pb = nullptr; 

    false && (*pb = true);  // ok at runtime. 
    AndL(false, (*pb = true)); // error at runtime! 
    AndR(false, (*pb = true)); // error at runtime! 
} 

伝統的な&&オペレータは、短絡評価をサポートしていますので、false && (*pb = true)は、実行時にOKになりますが、以下の2つのケースではありません。「短絡評価」を `fold expressions`でも利用できるようにする方法は?

作成方法短絡評価fold expressionsで利用できますか?

+9

ここでの問題は、折り畳み式ではありません。 'constexpr bool AND(bool a、bool b){return a && b;}'と試してみてください。問題は、関数を呼び出す前にすべての引数を評価しなければならず、渡される*結果*です。 – Quentin

+0

新しい 'pb'は決してありません。すべての' * pb = true'は未定義の動作です。 –

+1

実行時評価の理由は '* pb = true'自体が' constexpr'ではないからです。 –

答えて

6

ここでの問題は、実際に起こっていることの誤解に過ぎません。

作成方法短絡評価も折り畳み式で利用できますか?

は、であり、折り畳み式で利用可能である。 (args && ...)は、(a && b && c && d)とまったく同じ規則に従います。つまり、dは、a,b、およびcがすべて真実と評価された場合にのみ評価されます。

これは2つのケースの実際の違いではありません。

false && (*pb = true);  // ok at runtime. 
AndL(false, (*pb = true)); // error at runtime! 

倍式は、その非倍対応とまったく同じことを行うが、これらの二つの文の間に1つの重要な違いがあります。最初は文式であり、2つ目は関数呼び出しです。そして、すべての関数の引数は、本体の開始が始まる前に評価されなければなりません。

だから、第二は同等autoです:

auto&& a = false; 
auto&& b = (*pb = true); 
(FORWARD(a) && FORWARD(b)); 

それが問題を引き起こしているという順序だ、ない折り畳み式(注記:ba前に評価することができます)。

これを透過的にするために、本当に必要なのは遅延引数です。これは複数の言語(たとえばScala)の言語ですが、C++ではサポートされていません。 - おそらく唯一そうでない場合は、ブール値だと仮定し、呼び出し可能であるそれらのタイプを「アンラップ」

template<typename... Args> 
constexpr bool AndL(Args&&... args) 
{ 
    return (... && FORWARD(args)()); 
} 

AndL([]{ return false; }, [&]{ return *pb = true; }); 

あなたは、これは任意の複雑な作ることができます:あなたは怠惰が必要な場合は、あなたができる最善のは、ラムダのすべてを包んで:

実際には、関数の引数評価が関数の前にあり、問題は折り畳まれた式ではありません。

関連する問題