user-defined conversion combined with argument-dependent lookup

B

Belebele

Suppose that I have a class that has a user-defined conversion to
std::string, and I would like to compare objects of that class to
"strings" (e.g. literals, std::strings):

class InUpperCase {
public:
operator std::string() const;
};

....
InUpperCase()=="a string"; // This does not compile.
// fine, bool operator==(InUpperCase const& , char const* );
// is not declared anywhere.

InUpperCase()==std::string("a string"); // This one does not compile
either,
// even though, there is a definition for an operator== in std
// that takes two std::strings.

I expected the second expression to compile fine due to ADL combined
with the user-defined conversion. Any idea why?
 
A

Alf P. Steinbach

* Belebele:
Suppose that I have a class that has a user-defined conversion to
std::string, and I would like to compare objects of that class to
"strings" (e.g. literals, std::strings):

class InUpperCase {
public:
operator std::string() const;
};

...
InUpperCase()=="a string"; // This does not compile.
// fine, bool operator==(InUpperCase const& , char const* );
// is not declared anywhere.

InUpperCase()==std::string("a string"); // This one does not compile
either,
// even though, there is a definition for an operator== in std
// that takes two std::strings.

I expected the second expression to compile fine due to ADL combined
with the user-defined conversion. Any idea why?

Consider

#include <string>

struct Foo
{
operator std::string() const { return ""; }
};

template< typename Ch >
void bar( std::basic_string<Ch> const& ) {}

int main()
{
bar( Foo() );
}

Template matching doesn't succeed.

When you're the one writing the bar() function you can always support
future classes like Foo e.g. by making the argument a
ConvertibleTo<std::string>, with each Foo class publicly derived from
ConvertibleTo<std::string>.

Cheers, & hth.,

- Alf
 
J

James Kanze

Suppose that I have a class that has a user-defined conversion to
std::string, and I would like to compare objects of that class to
"strings" (e.g. literals, std::strings):
class InUpperCase {
public:
operator std::string() const;
};
...
InUpperCase()=="a string"; // This does not compile.
// fine, bool operator==(InUpperCase const& , char const* );
// is not declared anywhere.
InUpperCase()==std::string("a string"); // This one does not compile
either,
// even though, there is a definition for an operator== in std
// that takes two std::strings.
I expected the second expression to compile fine due to ADL combined
with the user-defined conversion. Any idea why?

The problem is that there is no actual function available. The
operator== defined on std::string are in fact templates, i.e.
template< typename CharT, ... >
bool
operator==( std::basic_string< CharT, ... > const& ...
In order for the operator to be available, the compiler must
instantiate it because of type deduction, and type deduction
doesn't take into account conversions (or only a very, very
limited set of conversions, e.g. array to pointer, and such).

If std::string weren't a template, then both of your examples
would work, since there's also a comparison between std::string
and char const*.
 
J

jg

The problem is that there is no actual function available. The
operator== defined on std::string are in fact templates, i.e.
template< typename CharT, ... >
bool
operator==( std::basic_string< CharT, ... > const& ...
In order for the operator to be available, the compiler must
instantiate it because of type deduction, and type deduction
doesn't take into account conversions (or only a very, very
limited set of conversions, e.g. array to pointer, and such).

If std::string weren't a template, then both of your examples
would work, since there's also a comparison between std::string
and char const*.

--
James Kanze (GABI Software) email:[email protected]
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

On the same page, can this operator== be explicitly instantiated ?
 
A

Abhishek Padmanabh

Suppose that I have a class that has a user-defined conversion to
std::string, and I would like to compare objects of that class to
"strings" (e.g. literals, std::strings):

class InUpperCase {
public:
operator std::string() const;

};

Instead of providing a conversion operator, why don't you provide
friend overload for operator== taking InUpperCase and std::string as
arguments?
 
J

James Kanze

On Dec 2, 1:19 am, James Kanze <[email protected]> wrote:
On the same page, can this operator== be explicitly
instantiated ?

I presume you mean the == operator for std::string. I think so,
but I'll admit that I've never done it.

I don't think that this will solve your problem, however. Even
if explicitly instantiated, the compiler will use type deduction
to determine whether the function is part of the overload set or
not, and type deduction will fail in your case.

The easiest solution is just to provide a simple wrapper in the
form of an operator== which uses your class.
 
B

Belebele

class InUpperCase {
Instead of providing a conversion operator, why don't you provide
friend overload for operator== taking InUpperCase and std::string as
arguments?

My intention, besides being clarity of representation, is to take
advantage of the existing facilities to avoid writing more boilerplate
code (as long as I don't muddle the implementation too much along the
way).

That's why I avoided the friend overload if I could.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top