2011-09-09 27 views
5

,才有可能和/或有用的用户定义文字以限定operator "" (...)为朋友功能?的C++ 0x,与操作者的朋友“”()

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

我在想“有用”,尤其是,因为operator ""应在命名空间中只能被定义规则的 - 而不是一个重要原因在于_开始的名称在全局命名空间保留。这是friend这里违反这条规则吗?所以,这个不太完美的封装没有好处,对吧?

回答

2

标准地址这直接在它提到用户定义的文字的声明任何限制的唯一场所,§13.5.8/ 2:

的声明,其声明符-id为一个文字的操作员-id应是一个命名空间范围的函数或函数模板(它可能是一个友元函数(11.3)),函数模板的显式实例化或专业化,或使用声明(7.3.3)的声明。

如果朋友也在名称空间范围内声明,那么在类或名称空间范围内的定义没有区别。请注意,在命名空间范围内没有要求定义的问题,您的问题与目前的措辞一致。

如果在命名空间内未声明,因为它无法通过ADL可以发现,朋友可以私下它是由正规不合格的名称查找范围类中使用。这是声明不是外部接口的文字操作符的唯一方法。

如果朋友是在类模板内部定义的,那么模板的两个实例将在名称空间范围内生成两个相同名称的函数,即使它们在类范围外都不可见,也会发生冲突。

+0

我真的认为我已经在某处读过它了,后缀*应该*只能在**命名空间**内声明。我不记得在哪里 - 但这只是一个建议,而不是要求。因此,这可能是“良好实践”的唯一提示。关于**模板**好友功能的好处。对于通常的* friend *模式,这不是问题,friend函数至少有一个参数是一个类实例本身 - 那么就没有命名问题。 – towi

+1

我记得在早期的立场文件中看到类似的东西。尝试n2378.pdf第5节:成语。在这里他们说:1.这些函数不是通过ADL通过文字调用而不是通过显式的操作符形式找到的。这将引诱在全球范围内的布局。 3.即使在不使用文字的代码中,这也会导致冲突。所以把文字操作放到一个命名空间中,并且使用一个使用指令将它们拉到全局级别。 – emsr

+0

我只是想说明你可以*不*在类中私有地使用朋友函数,参见[这个问题](http://stackoverflow.com/questions/8207633/whats-the-scope-of-inline-friend -功能)。 – Xeo

0

根据标准,是的,朋友声明应该是合法的。 顺便说一句,用户代码的名称很好,因为即使在全局名称空间中它也以下划线开头。

friend声明将允许操作员访问类的私有数据。

,我开始怀疑,朋友字面运营商的效用。由于用户定义的运算符只能有少量参数列表,因此无法将类放入参数中。因此,现在有依赖于参数的查找方式来找到正确的功能。我对吗?

+0

我觉得ADL可以使用,但必须寻找一个'为const char无论你的运营商是为定义*'说法或。但无论如何,我也怀疑它的实用性:好吧,您可以访问私人数据,但是您仍然需要调用构造函数。顺便说一句:johannes(其他anwers评论)指出,名称不是'_puzzle',而是'运算符'“_puzzle',因此不会以下划线开头。 – towi

+0

是的,根据13.5。对于文字操作员来说,8/7定期查询将占上风。我遇到名称问题。我在17.6.4.3.5挂了电话,它保留了文字后缀*,没有*前面的下划线。 – emsr

+1

我认为他们设计的主要目的是让他们允许一个库的唯一实现,比如说十进制。用户定义的文字操作符为词法分析器提供了一个钩子。 – emsr

1

在情况下,它有助于语法,这里是我如何在一个类中,操作人员本身是一个命名空间声明友用户定义的字面操作:

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; 

}; 

用户拉在运营商与using namespace literals;声明只有当他们想要它。 (实际上,所有这些都在父命名空间中,但你明白了)。