I have a question about complex numbers in standard library. Why there are both complex::real/imag member functions and std::real/imag global funcctions? consider: complex<double> cd(1,2); double r = cd.real(); r = real(cd); double i = cd.imag(); i = imag(cd);
>From point of OO view, it is obvious the real() and imag() should be
part of member functions. What is the benefit of global ones?
Thanks, -- Saeed Amrollahi
-- [ comp.std.c++ is moderated. To submit articles, try just posting with ] [ your news-reader. If that fails, use mailto:std-...@netlab.cs.rpi.edu] [ --- Please see the FAQ before posting. --- ] [ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
On 26 Okt., 20:14, Saeed Amrollahi <amrollahi.sa...@gmail.com> wrote:
> I have a question about complex numbers in standard library. Why there > are both complex::real/imag > member functions and std::real/imag global funcctions? consider: > complex<double> cd(1,2); > double r = cd.real(); > r = real(cd); > double i = cd.imag(); > i = imag(cd);
> >From point of OO view, it is obvious the real() and imag() should be
> part of member functions. > What is the benefit of global ones?
The member functions are natural for a language with classes, like C++, therefore the member functions exist. The free function real and imag exist to match the free functions of C99 in their *generic* forms from 7.22 <tgmath.h>. With C++0x on all generic C99 complex functions will have a pendant in <complex> (Nearly all: fabs is missing because of LWG defect 595).
HTH & Greetings from Bremen,
Daniel Krügler
-- [ comp.std.c++ is moderated. To submit articles, try just posting with ] [ your news-reader. If that fails, use mailto:std-...@netlab.cs.rpi.edu] [ --- Please see the FAQ before posting. --- ] [ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
> On 26 Okt., 20:14, Saeed Amrollahi <amrollahi.sa...@gmail.com> wrote:
> > I have a question about complex numbers in standard library. Why there > > are both complex::real/imag > > member functions and std::real/imag global funcctions? consider: > > complex<double> cd(1,2); > > double r = cd.real(); > > r = real(cd); > > double i = cd.imag(); > > i = imag(cd);
> > >From point of OO view, it is obvious the real() and imag() should be
> > part of member functions. > > What is the benefit of global ones?
> The member functions are natural for a language with classes, like > C++, therefore the member functions exist. The free function real > and imag exist to match the free functions of C99 in their *generic* > forms from 7.22 <tgmath.h>. With C++0x on all generic C99 complex > functions will have a pendant in <complex> (Nearly all: fabs is > missing > because of LWG defect 595).
> HTH & Greetings from Bremen,
> Daniel Krügler
> -- > [ comp.std.c++ is moderated. To submit articles, try just posting with ] > [ your news-reader. If that fails, use mailto:std-...@netlab.cs.rpi.edu] > [ --- Please see the FAQ before posting. --- ] > [ FAQ:http://www.comeaucomputing.com/csc/faq.html ]
Hi Daniel Thank you for your feedback.
So, the free functions real() and imag() are there just for C/C++ compatibility. For new abstractions let say run-time rational numbers, we don't need to such compatibility, because there is no rational number related functions in C, then we don't have to worry about these things. Right?
Thanks in advance, -- Saeed Amrollahi
-- [ comp.std.c++ is moderated. To submit articles, try just posting with ] [ your news-reader. If that fails, use mailto:std-...@netlab.cs.rpi.edu] [ --- Please see the FAQ before posting. --- ] [ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
On 27 Okt., 20:14, Saeed Amrollahi <amrollahi.sa...@gmail.com> wrote:
> On Oct 27, 12:26 am, Daniel Krügler <daniel.krueg...@googlemail.com> > wrote: > So, the free functions real() and imag() are there just for C/C++ > compatibility.
Yes, exactly.
> For new abstractions let say run-time rational numbers, we don't need > to such compatibility, because there is no rational number related functions > in C, then we don't have to worry about these things. Right?
This is correct.
HTH & Greetings from Bremen,
Daniel Krügler
-- [ comp.std.c++ is moderated. To submit articles, try just posting with ] [ your news-reader. If that fails, use mailto:std-...@netlab.cs.rpi.edu] [ --- Please see the FAQ before posting. --- ] [ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
On 27 Okt., 20:14, Saeed Amrollahi <amrollahi.sa...@gmail.com> wrote:
On Oct 27, 12:26 am, Daniel Krügler <daniel.krueg...@googlemail.com> wrote: So, the free functions real() and imag() are there just for C/C++ compatibility.
Yes, exactly.
For new abstractions let say run-time rational numbers, we don't need to such compatibility, because there is no rational number related functions in C, then we don't have to worry about these things. Right?
This is correct.
That does imply that it would be better to use the member functions in templates than the free functions, since other complex-like classes that the template may be useful for are likely to have the member functions, but not free function overloads, right?
-- [ comp.std.c++ is moderated. To submit articles, try just posting with ] [ your news-reader. If that fails, use mailto:std-...@netlab.cs.rpi.edu] [ --- Please see the FAQ before posting. --- ] [ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
> On 27 Okt., 20:14, Saeed Amrollahi <amrollahi.sa...@gmail.com> wrote:
> On Oct 27, 12:26 am, Daniel Krügler <daniel.krueg...@googlemail.com> > wrote: > So, the free functions real() and imag() are there just for C/C++ > compatibility.
> Yes, exactly.
> For new abstractions let say run-time rational numbers, we don't need > to such compatibility, because there is no rational number > related functions > in C, then we don't have to worry about these things. Right?
> This is correct.
> That does imply that it would be better to use the member functions in > templates than the free functions, since other complex-like classes > that the template may be useful for are likely to have the member > functions, but not free function overloads, right?
I don't know whether a clear answer to that question exists, it depends on whether there is a commonly accepted concept of a complex type. Another perspective to the same problem is that especially complex types are typically near to built-in types (in C they are built-in's) and this may cause implementors to develop them such that no need for a class type exists. This kind of thinking has a long tradition in C++ and if you check out the last draft for decimal support in C++
you will observe that the chosen interface corresponds to non-class types or in other words: If the decimal type is implemented as non-class type you won't notice the difference if the type is used "normally", e.g. by not attempting to call operators explicitly. From this POV I would expect that third-party implementations of a complex type would tend to use the same strategy and would provide non-member functions of the real and imag observers as well. The same idiom can be recognized by observing that basically no abs function is realized as a member function. One could also say that it might have been not such a good idea that std::complex did provide real and imag as member functions at all, because they are somewhat redundant in the presence of the free observer functions.
Returning to your question: I don't expect that a template code for complex-like types would necessarily attempt to get access to the real and imaginary part of the number by member functions. But a library might consider to use SFINAE tricks to determine whether access is possible by member functions and otherwise might attempt to fall-back to the free function access (or vice versa).
HTH & Greetings from Bremen,
Daniel Krügler
-- [ comp.std.c++ is moderated. To submit articles, try just posting with ] [ your news-reader. If that fails, use mailto:std-...@netlab.cs.rpi.edu] [ --- Please see the FAQ before posting. --- ] [ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
> That does imply that it would be better to use the member functions in > templates than the free functions, since other complex-like classes > that the template may be useful for are likely to have the member > functions, but not free function overloads, right?
The general trend I'm seeing (for all templates, not just things like complex) is to use free functions. That way, your template can cover all types - even those without member functions. Because I can always add free functions, but I can't always add member functions (ie to classes that aren't 'mine', etc).
And you can also add a default free impl that calls the member impl:
If TheComplexImUsing has a real() member function, I don't do anything. If it doesn't, then I implement a specialized real (TheComplexImUsing) function.
Tony
-- [ comp.std.c++ is moderated. To submit articles, try just posting with ] [ your news-reader. If that fails, use mailto:std-...@netlab.cs.rpi.edu] [ --- Please see the FAQ before posting. --- ] [ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
>> That does imply that it would be better to use the member functions in >> templates than the free functions, since other complex-like classes >> that the template may be useful for are likely to have the member >> functions, but not free function overloads, right?
> The general trend I'm seeing (for all templates, not just things like > complex) is to use free functions. That way, your template can cover > all types - even those without member functions. Because I can always > add free functions, but I can't always add member functions (ie to > classes that aren't 'mine', etc).
And here again we get back to the classic debate of what belongs as member functions of a class and what belongs as free functions. In many cases, for those who understand basic OO concepts, member functions often syntacticly make more sense than free functions. Microsoft's Intellesense system, and others like it make it easier to use member functions when available.
There are however a few big problems with member functions. One is that those functions that really do not benefit from having direct access to private members have such access anyway. For code maintenence reasons, it is usually preferable if only functions that need such acess have it, so that fewer functions actually use the private members, making it far easier to change them later if needed. Obviously, there is a tradeoff here, and needs is somewhat subjective. If a function can be implemented without acess, but it is far more complicated than if it had access to the private members, then perhaps it should have that access, etc.
If there were a nice way to make pseudo-member functions that did not have private acess, that would aleviate the problem. It may also potentially aleviate the other problem, that third party extentions cannot add member functions without using inheirtance. This is both good and bad. On one hand letting everybody inject additional functions as member functions sounds like it would become problematic, as all such functions are effectively in the same namespace. But it prevents third parties from adding new functions access like member functions even if they syntactically would make sense as them.
When I first heard of the concept proposal, I was under the impression that at least for deduced contexts this problem could be solved. I was under the impression that except for some operators, all functions in a concept would be pseudo-member functions, becoming calls to the real member function or to the definition in the concept_map. This made good sense to me. through this mechanism, one could add pseudo-member functions to any existing class, or even to built-in types, and things would just work, at least in contrained contexts. But apparently others seem to think that many functions in concepts should be pseudo-free functions instead, mapping to the real free function, or to the definition in the concept_map as applicable.
I also have some namespacing concerns with free functions. Free functions can be used in two different ways. I'll show these by example.
That sort of does not cause namespace issues. When I define my new complex-like type that is comaptible enough that many templates designed for std::complex can use it, I simply inject a new overload into namespace std, which I am explicitly permitted to do.
Here, ADL is being used. Injecting an overload into namespace std will do nothing here, since the compiler will be looking in my namespace for real and imag. Thus in some sense, now I need a my_ns::real(my_complex) function, when it is conceptually an overload of std::real, and thus ought to belong there. In some sense then my namespace is being infringed upon. I would not be objecting to the infringment upon the ::my_ns::my_complex namespace of member functions, since my goal is compaibilty, but infringing the ::my_ns namespace so that ::my_ns::my_complex can be compatible seems wrong.
Even a template that autocalls member functions being present in namespace std would not prevent the polluting of ::my_ns, since that template function would never even be considered if ADL style is being used.
-- [ comp.std.c++ is moderated. To submit articles, try just posting with ] [ your news-reader. If that fails, use mailto:std-...@netlab.cs.rpi.edu] [ --- Please see the FAQ before posting. --- ] [ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
> That sort of does not cause namespace issues. When I define my new > complex-like type that is comaptible enough that many templates designed for > std::complex can use it, I simply inject a new overload into namespace std, > which I am explicitly permitted to do.
Nope, your are not permitted to do that. The only thing you could do without violating the standard is to provide specializations of real and imag for a user-defined type, [namespace.std]/1:
"[..] A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type of external linkage and the specialization meets the standard library requirements for the original template and is not explicitly prohibited."
There exists no permission regarding adding overloads to namespace std and the truncated first sentence of [namespace.std]/1 is very strict here:
"The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified.[..]"
namespace soemthing{ template<typename T> T conj(const T& t) { using std::real; using std::imag; return T(real(t), -imag(t)); } }
and ensuring that both free functions are in scope during instantiation.
HTH & Greetings from Bremen,
Daniel Krügler
-- [ comp.std.c++ is moderated. To submit articles, try just posting with ] [ your news-reader. If that fails, use mailto:std-...@netlab.cs.rpi.edu] [ --- Please see the FAQ before posting. --- ] [ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
> That sort of does not cause namespace issues. When I define my new > complex-like type that is comaptible enough that many templates designed for > std::complex can use it, I simply inject a new overload into namespace std, > which I am explicitly permitted to do.
> Here, ADL is being used. Injecting an overload into namespace std will do > nothing here, since the compiler will be looking in my namespace for real > and imag. Thus in some sense, now I need a my_ns::real(my_complex) function, > when it is conceptually an overload of std::real, and thus ought to belong > there. In some sense then my namespace is being infringed upon. I would not > be objecting to the infringment upon the ::my_ns::my_complex namespace of > member functions, since my goal is compaibilty, but infringing the ::my_ns > namespace so that ::my_ns::my_complex can be compatible seems wrong.
template<typename T> T conj(const T& t) { using namespace std;
return T(real(t), -imag(t));
}
I've seen this form a few times (if I recall it correctly), particularly for swap() which is sometimes injected into std::, sometimes not, depending on implementor. I think this then catches both cases, favouring the T version of real ()/imag() if it exists (via ADL).
I agree with you that, in general, the right thing to do is to overload std::real(), as that is the context of what you are implementing. Otherwise a function like real(t) could be anything - not related to complex numbers at all...
Tony
-- [ comp.std.c++ is moderated. To submit articles, try just posting with ] [ your news-reader. If that fails, use mailto:std-...@netlab.cs.rpi.edu] [ --- Please see the FAQ before posting. --- ] [ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
>> That sort of does not cause namespace issues. When I define my new >> complex-like type that is comaptible enough that many templates designed >> for >> std::complex can use it, I simply inject a new overload into namespace >> std, >> which I am explicitly permitted to do.
> Nope, your are not permitted to do that. The only thing you could > do without violating the standard is to provide specializations > of real and imag for a user-defined type, [namespace.std]/1:
> "[..] A program may add a template specialization for any standard > library template to namespace std only if the declaration depends > on a user-defined type of external linkage and the specialization > meets the standard library requirements for the original template > and is not explicitly prohibited."
I was aware of this case, but was under the impression that overloads for user defined types were also permitted. The underlying logic being the same. I suppose that would not be needed if all functions where adding an overload for a user defined type could be useful are actually function templates, so roughly the same thing could be accomplished with adding a specialization.
-- [ comp.std.c++ is moderated. To submit articles, try just posting with ] [ your news-reader. If that fails, use mailto:std-...@netlab.cs.rpi.edu] [ --- Please see the FAQ before posting. --- ] [ FAQ: http://www.comeaucomputing.com/csc/faq.html ]