Я создал шаблонный класс с именем binding_condition, чтобы можно было абстрагировать условия для одного объекта. В настоящее время она работает с передачей лямбды и любых переменных, которые необходимо проверить, но я считаю, что лямбда вводит в заблуждение, поскольку она должна захватывать переменные, на которые я ссылаюсь.
например:
bool someVal = true;
int h = 10;
double p = 99.8;
char c = 'C';
binding_condition<bool> bc(
[] (bool b)
{ return b; },
someVal);
binding_condition<bool, int> bc2(
[] (bool b, int i)
{ return b && (i > 9); },
someVal, h);
binding_condition<bool, int, double> bc3(
[] (bool b, int i, double d)
{ return b && (i > 9) && (d < 100); },
someVal, h, p);
binding_condition<bool, int, double, char> bc4(
[] (bool b, int i, double d, char c)
{ return b && (i > 9) && (d < 100) && c == 'C'; },
someVal, h, p, c);
Это позволяет мне абстрагировать некоторые сложные условия в одно имя:
if (ThisComplexCondition) ...
else if (ThisOtherComplexCondition ...
...
Однако мне интересно, есть ли способ, с помощью шаблонов выражений или каким-либо другим методом, разрешить такой синтаксис:
binding_condition<bool, int, double> ComplexCondition = myClass.isTrue() && someThing.id < 100 && someDouble > 30.2;
Я понимаю, что приведенное выше выражение не особенно креативно, но рассмотрим следующее:
// analyzing chords in music to roman numeral notation, detect modulations, etc
// isChordRelatedToKey (the chord can be made from the current key
// isNeopolitan (the chord is a bii6 of the current key
// is major
// letter() is II/ii (ie C# major in C major is not a neapolitan, but Db major is)
// isSecondaryDominant
// chord is major
// chord is dominant of next chord (requires a new temporary key of next chord
// isSecondaryDiminished
// chord is diminished, and is the viio of the next chord
// all other forms of secondary, which means a ii/V in C major is A minor, which is also the vi of the key, and the iii/IV is also A minor
// nested secondary chords ie I - V - V/V - vii/V/V (C major, G major, D major, C# diminished)
// isModulation
// the current string of chords is not related to the current Key anymore
Я хочу реализовать какую-то машину состояний, упаковать эти ограничения в объекты и просто проверить как:
if (isModulation) ...
if (isSecondary) ... // recursive
if (isChordNoRelation) ... // some chord that makes no sense from previous string
Но ребенок шагает за один раз. Прямо сейчас я просто хочу знать, могу ли я назначить и сохранить выражение с любыми переменными / функциями, на которые есть ссылки в этом выражении.
Это возможно?
Что не так с лямбда-замыканиями, захватом переменных? Вам не нужно передавать их как параметры. В вашем первом примере вы можете сделать это:
bool someVal = true;
int h = 10;
double p = 99.8;
char c = 'C';
auto bc4 = [&](){return someVal && (h > 9) && (p < 100) && c == 'C';};
//later:
if(bc4())
{
/*...*/
}
и для второго примера:
auto ComplexCondition = [&]() { return myClass.isTrue() && someThing.id < 100 && someDouble > 30.2;};
Замыкания с использованием лямбда-выражений, которые захватывают упомянутые переменные по ссылке, поэтому значения оцениваются, когда вызывается оператор замыкания ():
bool someVal = true;
int h = 10;
double p = 99.8;
char c = 'C';
auto bc4 = [&](){return someVal && (h > 9) && (p < 100) && c == 'C';};
if(bc4()) //gives true
{ /* ... */ }
p *= 2;
if (bc4()) {} //gives false, since p > 100
Других решений пока нет …