荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Version (Who makes history and why), 信区: Program
标  题:  [C++]guiding declarations  (转载)
发信站: 荔园晨风BBS站 (Tue Mar 25 18:20:20 2003), 站内信件

以下文章就是写的可以解决operator<<
在bcb中unresolved的方法~~~

【 以下文字转载自 C++Builder 讨论区 】
发信人: weck (光), 信区: C++Builder
标  题: [C++]guiding declarations
发信站: BBS 水木清华站 (Mon Dec 17 20:30:50 2001)

guiding declarations
The Standard removes the notion of guiding declarations. Programmers have be
en using guiding declarations for years without knowing the word. Absence of
 guiding declarations (as dictated by the Standard) may change how programs
behave!
The notion of guiding declarations arose from the old C++ model of templates
. In this model, a program was completely compiled first, and then if any en
tities were missing, the compiler looked for templates that could be instant
iated as the missing entities. In particular, there was no distinction betwe
en an ordinary function and a specialization of a template function. The ord
inary function syntax was used to declare specializations. Furthermore, an o
rdinary function prototype could be used to declare a function that was supp
osed be instantiated from a template function. For instance, consider the fo
llowing fragment.
      template<class T> void f( T x ) {}  // (1)
    void f( int x );     // (2)
    void f( void * x );     // (3)
In the old C++ semantic model, if no definition was found to go with declara
tion on (2), then the compiler would instantiate the template on the declara
tion on (1) to provide the definition. The same would be done for (3). (2-3)
 were not, however, redundant because they participated in overload resoluti
on.
Given a function call f(2), the compiler would use (2) and (3) to guide over
load resolution. Thus those lines were later called guiding declarations.
To summarize: syntactically, guiding declaration is a declaration that would
 be a full specialization if it were prefixed by the full specialization syn
tax template <>. Semantically, it is considered an instance of a template de
claration, to be used to guide overload resolution.
Removing guiding declarations from a program requires a little thought. Ther
e are four options, and the right one depends upon the programmer's intent.
No change
The lazy option is to not change the program at all. In this case, what were
 gary function syntax was used to declare specializations. Furthermore, an o
rdinary function prototype could be used to declare a function that was supp
osed be instantiated from a template function. For instance, consider the fo
llowing fragment.
      template<class T> void f( T x ) {}  // (1)
    void f( int x );     // (2)
    void f( void * x );     // (3)
In the old C++ semantic model, if no definition was found to go with declara
tion on (2), then the compiler would instantiate the template on the declara
tion on (1) to provide the definition. The same would be done for (3). (2-3)
 were not, however, redundant because they participated in overload resoluti
on.
Given a function call f(2), the compiler would use (2) and (3) to guide over
load resolution. Thus those lines were later called guiding declarations.
To summarize: syntactically, guiding declaration is a declaration that would
 be a full specialization if it were prefixed by the full specialization syn
tax template <>. Semantically, it is considered an instance of a template de
claration, to be used to guide overload resolution.
Removing guiding declarations from a program requires a little thought. Ther
e are four options, and the right one depends upon the programmer's intent.
No change
The lazy option is to not change the program at all. In this case, what were
 guiding declarations now become declarations for ordinary functions, distin
ct from the template declaration. The ordinary functions require their own d
efinitions, as they are not considered to be related to the template. Our ex
ample, with only the comments updated, is shown below:
   template<class T>
 void f( T x ) {}    // Template function
 void f( int x );    // Ordinary function
 void f( void * x ); // Ordinary function
The two ordinary functions require definitions elsewhere, or the program wil
l fail to link.
Use specialization
Another option is to change the declarations to specializations.
   template<class T> void f( T x ) {} // Template function
 template<> void f( int x );   // Specialization of template
 template<> void f( void * x );  // Specialization of template
The two specializations require definitions elsewhere, or the program will f
ail to link. This is not really much of an improvement over not changing the
 program. The decision, therefore, should be based upon whether the original
 intent was to define non-template functions or specializations.
Remove guiding declarations
The third option is to remove the guiding declarations. This is the appropri
ate option if the original intent was only to provide guidance for overload
resolution and not to provide overloaded or specialized definitions. The Sta
ct from the template declaration. The ordinary functions require their own d
efinitions, as they are not considered to be related to the template. Our ex
ample, with only the comments updated, is shown below:
   template<class T>
 void f( T x ) {}    // Template function
 void f( int x );    // Ordinary function
 void f( void * x ); // Ordinary function
The two ordinary functions require definitions elsewhere, or the program wil
l fail to link.
Use specialization
Another option is to change the declarations to specializations.
   template<class T> void f( T x ) {} // Template function
 template<> void f( int x );   // Specialization of template
 template<> void f( void * x );  // Specialization of template
The two specializations require definitions elsewhere, or the program will f
ail to link. This is not really much of an improvement over not changing the
 program. The decision, therefore, should be based upon whether the original
 intent was to define non-template functions or specializations.
Remove guiding declarations
The third option is to remove the guiding declarations. This is the appropri
ate option if the original intent was only to provide guidance for overload
resolution and not to provide overloaded or specialized definitions. The Sta
  friend ostream& operator<<( ostream&, const King<T>& );
 };
 template<class T>
 ostream& operator<<cond. In the old model, these steps were tangled, and th
e guiding declarations assisted untangling.
Explicit specification
The fourth option is necessary when the guiding declaration is a friend decl
aration. For purposes of discussion, below is a sample program that requires
 a friend declaration. The program prints how much money King Babar has.
   #include <iostream>
 using namespace std;
   // Forward declaration of King required for forward declaration of operat
or<<.
 template<class T>
 class King;
   // Forward declaration of operator<< required for definition of class Kin
g.
 template<class T>
 ostream& operator<<( ostream& o, const King<T>& king );
   template<class T>
 class King { T money; public: King( T value ) : money(value) {}
  // Guiding declaration
  friend ostream& operator<<( ostream&, const King<T>& );
 };
 template<class T>
 ostream& operator<<( ostream& o, const King<T>& king ) {
  // operator<< accesses private member king.money.
  return o << king.money;
 }
 main() {
  King<int> Babar(1000000);
  cout << Babar << endl;
 }
This program compiles but fails with a link-time error in ANSI mode. The pro
blem is the guiding declaration, which is not recognized in this mode.
   Unresolved: operator << ( std::basic_ostream<char,
         std::char_traits<char>> &,
         const King<int>& );
Notice that there is no mention of template parameters here, which indicates
 that the missing function is a non-template function. This implies that the
 compiler resolved a call to a non-template prototype. The offending prototy
pe is of course: friend ostream& operator<<( ostream&, const King<T>& ); Tho
ugh this prototype occurs inside a template, the prototype itself is not a t
emplate nor a template instance. When guiding declarations were enabled, thi
Notice that there is no mention of template parameters here, which indicates
 that the missing function is a non-template function. This implies that the
 compiler resolved a call to a non-template prototype. The offending prototy
pe is of course: friend ostream& operator<<( ostream&, const King<T>& ); Tho
ugh this prototype occurs inside a template, the prototype itself is not a t
emplate nor a template instance. When guiding declarations were enabled, thi
s as an instance of the template function. But with guiding declarations dis
abled, it is an ordinary friend function prototype that is seen when class K
ing<T> is instantiated for a type T. The lack of a definition for this ordin
ary friend function results in the unresolved symbol. To fix the problem, th
e friend declaration must be changed so that it is an instance of the templa
te and not a non-template function. The right way to write it is use explici
t specification of the template arguments:
   friend ostream& operator<< <T>( ostream&, const King<T>&);
This says that the friend is operator<<, instantiated for the type T for whi
ch class King is being instantiated. In order to conform to the Standard, yo
u must "say what you mean."


--
                      *
          *                                  *
                          *             *
                      no more to say
                  ★     just wish you   ★
                            good luck

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.1.50]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店