5

Will it be possible and/or useful to define an operator "" (...) as a friend function?

class Puzzle {
  friend Puzzle operator "" _puzzle(const char*, size_t);
  ...
};
void solve(Puzzle);
int main() {
  solve("oxo,xox"_puzzle);
};

I am thinking about "useful" especially, because of the rule that operator "" shall be defined in a namespace only -- not the least because identifiers beginning with _ are reserved in global namespace. Is this friend breaking this rule here? So, there would be no benefit with this not-quite encapsulation, right?

Xeo
  • 129,499
  • 52
  • 291
  • 397
towi
  • 21,587
  • 28
  • 106
  • 187

3 Answers3

2

The Standard addresses this directly in the only place it mentions any restrictions on the declarations of user-defined literals, §13.5.8/2:

A declaration whose declarator-id is a literal-operator-id shall be a declaration of a namespace-scope function or function template (it could be a friend function (11.3)), an explicit instantiation or specialization of a function template, or a using-declaration (7.3.3).

If the friend is also declared at namespace scope, then there is no distinction between definition in class or namespace scope. Note that there is no requirement for definition at namespace scope, which your question as currently worded asserts.

If not declared at namespace scope, since it cannot be found by ADL, the friend could be used privately inside the class where it is scope by regular unqualified name lookup. This is the only way of declaring a literal operator which is not an external interface.

If the friend is defined inside a class template, then two instantiations of the template will generate two identically-named functions at namespace scope, which collide even though they are both invisible outside the class scope.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • I really thought I've read it somewhere, that suffixes *should* only be declared inside a **namespace**. I can not remember where -- but it was only a suggestion, not a requirement. And therefore, it was probably a only tip for "good practice". Good point about the **template** friend function. This is not an issue with the usual *friend* pattern, what at least one of the arguments to the friend function is a class instance itself -- then there is no naming issue. – towi Sep 11 '11 at 09:39
  • 1
    I remember seeing something like this in the earlier position papers. Try n2378.pdf section 5: An Idiom. Here they say: 1. These functions are not found through ADL when called through literals instead of explicit operator form. 2. This would tempt placement in global. 3. This would lead to conflicts even in code that doesn't use the literal. 4. So put the literal ops in a namespace and put a using directive to pull them to global level. – emsr Sep 12 '11 at 19:01
  • I just wanted to note that you can *not* use the friend function privately inside the class, see [this question](http://stackoverflow.com/questions/8207633/whats-the-scope-of-inline-friend-functions). – Xeo Dec 05 '11 at 23:48
1

In case it helps with syntax, here is how I declare a friend user-defined literal operator in a class, where the operator itself is in a namespace:

class Integer;
namespace literals {
  Integer operator "" _I (const char *);
}

// Infinite precision integer 
class Integer {
  public:

  // Basic constructor & destructor
   Integer ();
  ~Integer ();

... rest of the interface ...

  // Literal operator
  friend Integer literals::operator "" _I (const char *);

  private:

  struct Detail;
  std::unique_ptr<Detail> detail;

};

Users pull in the operator with a using namespace literals; statement only if they want it. (And, actually, all of this is in a parent namespace, but you get the idea).

wjl
  • 7,519
  • 2
  • 32
  • 41
0

According to the standard, yes, a friend declaration should be legal. By the way, the name is fine for user code since it starts with an underscore even in global namespace.

The friend declaration would allow the operator to access class-private data.

I am beginning to question the usefulness of friend literal operators. Because the user-defined operators can only have a few argument lists there is no way to put the class in the arguments. So there is now way for argument dependent look-up to find the right function. Am I right?

emsr
  • 15,539
  • 6
  • 49
  • 62
  • I think ADL could be used, but it has to look for a `const char*` argument or whatever your operator is defined for. But anyway, I doubt the usefulness, too: Ok, you can access private data, but you need to call a constructor anyway. BTW: johannes (other anwers comments) pointed out, that the name is not `_puzzle`, but `operator "" _puzzle` and therefore would not start with an underscore. – towi Sep 10 '11 at 11:51
  • Yes, according to 13.5.8/7 regular lookup will prevail for literal operators. I get the name issue. I got hung up on 17.6.4.3.5 which reserves literal suffixes *without* a leading underscore to the implementation. – emsr Sep 10 '11 at 18:26
  • 1
    I think the main thing they were designed for is that they would have allowed a library-only implementation of, say, decimal. User-defined literal operators offer a hook into the lexer. – emsr Sep 10 '11 at 18:32