26

As a prior note: This is not something I would 'desire' to achieve; more-so a question related to if it's actually possible.

N.B. I understand (and have used) Operator Overloding in C++. For example:

std::ostream& operator<<(std::ostream& os, const T& obj){ return os; }

Is it possible to define a custom ASCII character to act as an operator?

For example, in a simple sense: use the grave accent (`) as an 'alias' for std::pow.

Whereby, the following statement would be valid/achievable:

std::cout << 2`3 << std::endl;

>> 8
John Saunders
  • 160,644
  • 26
  • 247
  • 397
Alfie J. Palmer
  • 827
  • 2
  • 15
  • 30
  • No. You can overload existing ones to do what you want, you could even fiddle with macros so the preprocessor replaces that accent with another operator. Whether that is a good idea is another thing though.. – stijn Mar 04 '15 at 09:12
  • 1
    Custom build of g++ ;-) – Matt Mar 04 '15 at 09:13
  • You could supply an operator for a [*user-defined literal*](http://en.wikipedia.org/wiki/C%2B%2B11#User-defined_literals) suffix, such that e.g. 2.3_pow meant 2^3 - you'd need to use the variadic template model, forming an instantiation ala `< '2', '.', '3' >`, or settle for "2.3"_pow and handle a `const char*` at runtime. It'd be tedious to write the operator template and ugly (even misleading given 2.3 looks like a float/double) in usage anyway.... – Tony Delroy Mar 04 '15 at 09:31
  • @TonyD An alternative would be `2_pow ->* 3` with an overloaded `->*` to mean "apply to." – Angew is no longer proud of SO Mar 04 '15 at 10:26
  • 2
    @Angew: could do that... or just `2_n ^ 3` (on [ideone](http://ideone.com/icodHV)), though there's a solid argument that's more confusing for hijacking bitwise-OR. – Tony Delroy Mar 04 '15 at 10:29
  • 1
    @TonyD I used `->*` because of its high precedence. You could take any operator with a suitable one. – Angew is no longer proud of SO Mar 04 '15 at 10:47
  • 3
    You are certainly aware that the _"S"_ in "ASCII" stands for _"standard"_? And that therefore _"custom ASCII character"_ is a contradiction in terms? (Just kidding.) – Lutz Prechelt Mar 04 '15 at 18:06
  • 3
    FYI Haskell has the feature you want; a web search for "infix operators in Haskell" should yield interesting reading. – Eric Lippert Mar 04 '15 at 19:12
  • @EricLippert why Haskell in particular? Lots of languages have infix operators - for example swift and scala. – Benjamin Gruenbaum Mar 04 '15 at 22:43
  • 5
    @BenjaminGruenbaum: Because Haskell is awesome? As is Scala of course. Swift I have insufficient data upon which to make a judgment. – Eric Lippert Mar 05 '15 at 00:58
  • Related questions (I previously listed these in meta discussion about this Q): Or not. http://stackoverflow.com/q/25513374/103167 http://stackoverflow.com/q/15090209/103167 http://codereview.stackexchange.com/q/23179/2150 http://stackoverflow.com/q/20861231/103167 http://stackoverflow.com/a/14782169/103167 – Ben Voigt Dec 04 '16 at 00:44

2 Answers2

72

You cannot introduce a character not present in the syntax, such as the backtick you mentioned. But there is a "named operator" trick with which you can introduce a "named operator" to achieve the following syntax:

std::cout << (2 <Pow> 3) << std::endl;

The trick relies on overloading < and > for a custom type, like this:

const struct PowOperator {} Pow;

struct PowInvoker
{
  int lhs;
};

PowInvoker operator< (int lhs, PowOperator)
{
  return {lhs};
}

int operator> (PowInvoker lhs, int rhs)
{
  return std::pow(lhs.lhs, rhs);
}

int main()
{
  std::cout << (2 <Pow> 3) << std::endl;
}

[Live example]

Notice that you cannot affect the precedence of these named operators: they will have the same precedence as <, <=, >, and >=. If you need different precedence, you'd have to use a different delimiter (which would probably not be as nicely readable).


Disclaimer

The above trick is "clever" code, it's pretty much an abuse of the C++ syntax. I took the question as a hypothetical "what is possible," and answered with an equally hypothetical "this is." I would not recommend using this in practice for such trivial matters as replacing std::pow or providing "novelty" syntax for the sake of it. The operator precedence caveat mentioned above is one reason; general unfamiliarity of the construct is another. Code quality is measured in the number of WTFs the code generates (fewer is better), and this trick generates a whole bunch of them (and big ones at that).

It still has its uses: for creating a Domain-Specific Language. There are cases in programming where embedding a DSL into C++ code is in order; in such cases (and only in such cases) would I consider using this.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • 35
    I'd savagely mutilate anyone who used that in "real" code, but +1 for an interesting answer to a hypothetical question. – ApproachingDarknessFish Mar 04 '15 at 09:26
  • 4
    @ApproachingDarknessFish Replacing `std::pow` is not what this is for, but it can provide a viable DSL for some situations. – Angew is no longer proud of SO Mar 04 '15 at 09:34
  • 2
    @Angew Interesting concept; thank you for the link to the 'named-operator' trick. I've never actually seen this done before. – Alfie J. Palmer Mar 04 '15 at 11:57
  • AFAICT -and it might be worth mentioning in your answer- it seems that you are still limited to using a valid idenitifier name for the name of your operator... does C++ allow for Unicode characters in legal identifiers? – Sled Mar 04 '15 at 16:12
  • 1
    @ArtB: I think that's compiler specific. C++ disallows a couple characters, requires a few, but all the rest are up to the compiler. – Mooing Duck Mar 04 '15 at 19:54
  • Also it occurs to me that one could use a macro `#define POW ->*Pow->*` which would be closer to what the OP asked for, and binds tighter. – Mooing Duck Mar 04 '15 at 19:55
  • @Angew I was wondering, is this (in a broad sense of the word) guaranteed to work? I.e., could something like operator precedence 'break' the code? – Sanchises Mar 04 '15 at 23:04
  • 1
    @sanchises Yes, operator precedence can indeed break it. Notice I (had to) put parentheses around the subexpression in the output statement. Named operators constructed in this way will always have the same precedence as `<`, `<=`, `>`, and `>=`. As Mooing Duck mentioned, you could use a different operator for delimiter to achieve more favourable binding (such as `->*`, the tightest-binding general-purpose infix operator). – Angew is no longer proud of SO Mar 05 '15 at 08:04
  • This hack deserves a "C++ Arcana Of The Year" award. – alecov May 21 '17 at 03:07
11

No, that is not possible. Even at the preprocessor level you are limited by the characters that form valid preprocessor tokens and macro names, and then the language grammar fixes the set of operators in the language.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Thanks for the prompt reply @Kerrek. I was convinced that it wasn't possible; just hadn't seen adequate information about the topic on the web. Thanks for clearing that up. :-) – Alfie J. Palmer Mar 04 '15 at 09:13