Re: declaring/defining op== for private nested class
On 8 Mrz., 20:17, Paul Bibbings <paul.bibbi...@gmail.com> wrote:
Consider the following sample code and output from an attempt to
compile it:
#include <string>
template<typename T>
class outer {
public:
explicit outer(T t) : h_(t) { }
bool equals(T t) { return t == h_; } // uses holder::op T&()/T()
Why does the function not have a const-qualifier?
private:
struct holder {
explicit holder(T t) : t_(t) { }
operator T&() { return t_; }
operator T() const { return t_; }
T t_;
// friend bool operator==(const T& t, const holder& h) {
// return t == h.t_;
// }
};
holder h_;
};
int main()
{
const char *c_str = "c_str";
outer<const char *> out(c_str);
out.equals(c_str);
std::string s("std::string");
outer<std::string> out2(s);
out2.equals(s); // line 31
}
16:22:32 Paul Bibbings@JIJOU
/cygdrive/d/CPPProjects/nano/test_link $g++ -o test test.cpp
test.cpp: In member function 'bool outer<T>::equals(T)
[with T = std::basic_string<char, std::char_traits<char>,
std::allocator<char> >]':
test.cpp:31: instantiated from here
test.cpp:9: error: no match for 'operator==' in 't ==
((outer<std::basic_string<char, std::char_traits<char>,
std::allocator<char> > >*)this)->outer<std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >::h_'
If I uncomment the friend op== then the code compiles successfully
but, as is, whilst the conversion operator holder::operator T&() is
made use of in the selection of the appropriate op== for the call
out.equals(c_str) [c_str = const char *], it is *not* for the later
call out2.equals(s) [s = std::string]. If my understanding is
correct, this failure is because op== for std::string is a template
function parameterized on CharT (e.g.), and conversion operators are
not considered in instantiating template functions (I think).
This is correct.
Having added the op== to account for this, however, I'm wondering now
about the options for declaring/defining it. Here, I have defined it
inline as a friend of holder, but this looks a little odd to me. I
have done it this way, perhaps in ignorance of all the possibilities.
It seems odd because, though declared as a friend of holder, op== does
not 'require' this friendship in the sense that holder's data is
public. Yet, without defining it as an inline friend I can't see what
other options there are. I'm thinking that it cannot be defined in
the nearest surrounding namespace scope as a non-friend because holder
is a *private* nested class of outer. Furthermore, in real code, I
would want to balance this with its counterparts op==(const holder&,
const T&) and op==(const holder&, const holder&), so it seems that it
must be a free function rather than a member.
I don't see the need for the symmetry of equality between
holder and T, because holder is only a private member
class of outer. Given this, you could define
struct holder {
bool operator==(const T& t) const {
return t == t_;
}
};
as a member operator== overload of holder, but you need to
exchange the arguments in your equals function (I added
a const qualification):
bool equals(T t) const {
return h_ == t;
}
If you would really like to have a symmetric function,
I don't see the reason why holder should not simply
provide a static (non-operator) member function:
bool equals(T t) const {
return holder::equals(t, h_);
}
struct holder {
...
static bool equals(const T& t, const holder& h) {
return t == h.t_;
}
};
So, my question is: is it the language, or is it my understanding,
that is seemingly limiting me in having to provide op== here as an
inline-defined friend of my nested private class.
There are several possible solutions to your problem.
HTH & Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]