クラステンプレート内で frinend 関数を定義した場合の名前の扱い
Every name first declared in a namespace is a member of that namespace. If a friend declaration in a non-local class first declares a class or function*1 the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by simple name lookup until a matching declaration is provided in that namespace scope (either before or after the class declaration granting friendship). If a friend function is called, its name may be found by the name lookup that considers functions from namespaces and classes associated with the types of the function arguments (basic.lookup.koenig). When looking for a prior declaration of a class or a function declared as a friend, scopes outside the innermost enclosing namespace scope are not considered. [Example:
// Assume f and g have not yet been defined. void h(int); namespace A { class X { friend void f(X); // A::f is a friend class Y { friend void g(); // A::g is a friend friend void h(int); // A::h is a friend // ::h not considered }; }; // A::f, A::g and A::h are not visible here X x; void g() { f(x); } // definition of A::g void f(X) { /* ... */} // definition of A::f void h(int) { /* ... */ } // definition of A::h // A::f, A::g and A::h are visible here and known to be friends } using A::x; void h() { A::f(x); A::X::f(x); // error: f is not a member of A::X A::X::Y::g(); // error: g is not a member of A::X::Y }http://www.kuzbass.ru:8086/docs/isocpp/dcl.html
As with non-template classes, the names of namespace-scope friend functions of a class template specialization are not visible during an ordinary lookup unless explicitly declared at namespace scope (class.friend). Such names may be found under the rules for associated classes (basic.lookup.koenig).*2
template<typename T> class number { number(int); //... friend number gcd(number& x, number& y) { /* ... */ } //... }; void g() { number<double> a(3), b(4); //... a = gcd(a,b); // finds gcd because number<double> is an // associated class, making gcd visible // in its namespace (global scope) b = gcd(3,4); // ill-formed; gcd is not visible }http://www.kuzbass.ru:8086/docs/isocpp/template.html
On some compilers (e.g. Borland, GCC) even single-inheritance seems to cause an increase in object size in some cases. If you are not defining a class template, you may get better object-size performance by avoiding derivation altogether, and instead explicitly instantiating the operator template as follows:
class myclass // lose the inheritance... { //... }; // explicitly instantiate the operators I need. template struct less_than_comparable<myclass>; template struct equality_comparable<myclass>; template struct incrementable<myclass>; template struct decrementable<myclass>; template struct addable<myclass,long>; template struct subtractable<myclass,long>;Note that some operator templates cannot use this workaround and must be a base class of their primary operand type. Those templates define operators which must be member functions, and the workaround needs the operators to be independent friend functions. The relevant templates are:
- dereferenceable<>
- indexable<>
- Any composite operator template that includes at least one of the above
As Daniel Krügler pointed out, this technique violates 14.6.5/2 and is thus non-portable. The reasoning is, that the operators injected by the instantiation of e.g. less_than_comparable
Header <boost/operators.hpp> Documentation - 1.36.0can not be found by ADL according to the rules given by 3.4.2/2, since myclass is not an associated class of less_than_comparable . Thus only use this technique if all else fails.
"associated class", "associated namespace" とは
- 基本型
- 両方なし
- クラス型
- associated class
- 基底クラス(間接も含む)
- associated namespace
- クラスが定義された名前空間
- associated class
- union, enum 型
- associated class
- クラスメンバだったら、そのクラス
- クラスメンバじゃなかったら無し
- associated namespace
- 定義された名前空間
- associated class
- ポインタ、配列
- ポインタが指すクラス、配列の要素となるクラスの associated class と associated namespace
- 関数
- 仮引数と返却値の型の associated class と associated namespace
- メンバ関数のポインタ
- 仮引数と返却値の型の associated class と associated namespace
- メンバを持っているクラスの associated class と associated namespace
- データメンバのポインタ
- メンバの型とメンバを持っているクラスの associated class と associated namespace
- テンプレート
For each argument type T in the function call, there is a set of zero or more associated namespaces and a set of zero or more associated classes to be considered. The sets of namespaces and classes is determined entirely by the types of the function arguments (and the namespace of any template template argument). Typedef names and using-declarations used to specify the types do not contribute to this set. The sets of namespaces and classes are determined in the following way:
- If T is a fundamental type, its associated sets of namespaces and classes are both empty.
- If T is a class type, its associated classes are the class itself and its direct and indirect base classes. Its associated namespaces are the namespaces in which its associated classes are defined.
- If T is a union or enumeration type, its associated namespace is the namespace in which it is defined. If it is a class member, its associated class is the member's class; else it has no associated class.
- If T is a pointer to U or an array of U, its associated namespaces and classes are those associated with U.
- If T is a function type, its associated namespaces and classes are those associated with the function parameter types and those associated with the return type.
- If T is a pointer to a member function of a class X, its associated namespaces and classes are those associated with the function parameter types and return type, together with those associated with X.
- If T is a pointer to a data member of class X, its associated namespaces and classes are those associated with the member type together with those associated with X.
- If T is a template-id, its associated namespaces and classes are the namespace in which the template is defined; for member templates, the member template's class; the namespaces and classes associated with the types of the template arguments provided for template type parameters (excluding template template parameters); the namespaces in which any template template arguments are defined; and the classes in which any member templates used as template template arguments are defined.(non-type template arguments do not contribute to the set of associated namespaces. )
If the ordinary unqualified lookup of the name finds the declaration of a class member function, the associated namespaces and classes are not considered. Otherwise the set of declarations found by the lookup of the function name is the union of the set of declarations found using ordinary unqualified lookup and the set of declarations found in the namespaces and classes associated with the argument types.
namespace NS { class T { }; void f(T); } NS::T parm; int main() { f(parm); // OK: calls NS::f }http://www.kuzbass.ru:8086/docs/isocpp/basic.html
When considering an associated namespace, the lookup is the same as the lookup performed when the associated namespace is used as a qualifier (namespace.qual) except that:
http://www.kuzbass.ru:8086/docs/isocpp/basic.html
- Any using-directives in the associated namespace are ignored.
- Any namespace-scope friend functions declared in associated classes are visible within their respective namespaces even if they are not visible during an ordinary lookup (class.friend).