You just encountered a bug that plagues most of the DSEL.
The issue is that you want a specific operator to be called, the one actually defined in your specific languages. However this operator already exist in C++, and therefore the normal rules of Lookup and Overload resolution apply.
The selection of the right operator is done with ADL (Argument Dependent Lookup), which means that at least one of the objects on which the operator apply should be part of the DSEL itself.
For example, consider this simple code snippet:
namespace dsel
{
class MyObject;
class MyStream;
MyStream operator<<(std::ostream&, MyObject);
}
int main(int, char*[])
{
std::cout << MyObject() << "other things here";
}
Because the expression is evaluated from left to right, the presence of dsel::MyObject
is viral, ie the dsel will here be propagated.
Regarding Xpressive
, most of the times it works because you use special "markers" that are Xpressive
type instances like (_w
) or because of the viral effect (for example "@" works because the expression on the left of >>
is Xpressive
-related).
Were you to use:
sregex re = "sip:" >> *(_w | '.') >> '@' >> *(_w | '.');
^^^^^^ ~~ ^^^^^^^^^^^
Regular Xpressive
It would work, because the right hand-side argument is "contaminated" by Xpressive
thanks to the precedence rules of the operators.
However here operator!
has one of the highest precedence. At such, its scope is restricted to:
`!"sip:"`
And since "sip:"
is of type char const[5]
, it just invokes the regular operator!
which will rightly conclude that the expression to which it applies is true
and thus evaluate to the bool
value false
.
By using as_xpr
, you convert the C-string into an Xpressive
object, and thus bring in the right operator!
from the Xpressive
namespace into consideration, and overload resolution kicks in appropriately.