invalid use of auto in expression ??

M

mdcb808

Hello all,

I was wondering if this was legit C++11x

std::map<std::string, int> m;
...

(1) if ((auto bar = m.find("bar")) == m.end()) std::cout << "bar not found\n";

breaking it down in 2 steps keeps my compiler happy:

(2) auto foo = m.find("foo");
if (foo == m.end()) std::cout << "foo not found\n";


Is this guided by the standard, or a limitation with my compiler?

Thanks
 
A

Alf P. Steinbach

Hello all,

I was wondering if this was legit C++11x

std::map<std::string, int> m;
...

(1) if ((auto bar = m.find("bar")) == m.end()) std::cout<< "bar not found\n";

breaking it down in 2 steps keeps my compiler happy:

(2) auto foo = m.find("foo");
if (foo == m.end()) std::cout<< "foo not found\n";


Is this guided by the standard, or a limitation with my compiler?

It has nothing to do with `auto`.

The above is analogous to

(int x = foo()) == 666

In general you can't put declarations within expressions. The support
for a declaration in a /condition/ is very rudimentary, and the
initializer is just converted to bool for the decision. Mostly it's only
useful for a `dynamic_cast` as initializer.

You're not using the name you attempt to declare, so it's difficult to
say how to express what you're attempting (but fail to show).

Maybe post separately about that.


Cheers & hth.,

- Alf
 
K

Kevin McCarty

Hello all,

I was wondering if this was legit C++11x

  std::map<std::string, int> m;
  ...

(1)  if ((auto bar = m.find("bar")) == m.end()) std::cout << "barnot found\n";

breaking it down in 2 steps keeps my compiler happy:

(2)  auto foo = m.find("foo");
     if (foo == m.end()) std::cout << "foo not found\n";

Is this guided by the standard, or a limitation with my compiler?

Thanks

I don't have a chapter and verse to cite, but I don't think the above
form (1) is allowed in either C++ 03 or 11 (neither with "auto" nor
with an actual explicit type). This won't compile either:

if ((int foo = getSomeInt()) == 5) { doSomething(foo); }


Perhaps you're thinking of this form, which is slightly less
featureful but does compile:

if (int foo = getSomeInt()) { doSomething(foo); }

This calls doSomething(foo) if a boolean conversion of the value
assigned to foo from getSomeInt() is true. It's a nice replacement
for

int foo = getSomeInt();
if (foo) { doSomething(foo); }

which keeps the scope of foo better-contained.


So I'd imagine that the following should work in C++ 11 (not tested)

if (auto foo = getSomething()) { doSomething(foo); }


This doesn't help with your particular example, though. On the other
hand, your example isn't using the value of 'bar' anyway, so you could
simply use

if (m.find("bar") == m.end()) std::cout << "bar not found\n";

- Kevin B. McCarty
 
M

mdcb808

Thanks you both answered my question, although I had to convince myself compiling Kevin's simple case so I was not day dreaming.
I guess what I had in mind was along:

map<string, MyObject *> mymap;

if ( (auto obj = mymap.find(key) ) == mymap.end() ) {
// deal with it
} else {
obj.do_work()
}

Cheers
 
V

Victor Bazarov

Thanks you both answered my question, although I had to convince myself compiling Kevin's simple case so I was not day dreaming.
I guess what I had in mind was along:

map<string, MyObject *> mymap;

if ( (auto obj = mymap.find(key) ) == mymap.end() ) {
// deal with it
} else {
obj.do_work()
}

I rarely use that form, and I don't remember whether 'obj' is still
declared in the 'else' block or not, so I would actually write (if it
were possible):

if ((auto obj = mymap.find(key) != mymap.end())
{
obj.do_work();
}
else
{
// deal with it
}

The more common idiom *I* use involves a pointer:

if (SomeType* pBlah = getThePointerSomehow())
{
// use the non-null pBlah
}
else
{
// even if 'pBlah' is still declared here, it's null,
// so no reason to involve that name
}

which should explain why I don't care to learn whether 'pBlah' would be
still declared in the 'else' part :)

Now, with your 'find/end' stuff, the only way I see to combine the
declaration/definition/initialization is to declare your own wrapper for
the "find" operation:

template<class C> struct find_wrapper {
C& co;
typename C::iterator it;
template<class W> find_wrapper(C& c, const W& w)
: co(c), it(c.find(w)) {}
// here is the key thing that allows declaring it in an 'if'
operator bool() const { return it != co.end(); }
typename C::iterator::value_type& obj() { return *it; }

void operator =(const find_wrapper&) {}
};

template<class C, class W>
find_wrapper<C> do_find(C& co, const W& w) {
return find_wrapper<C>(co, w);
}

#include <map>

int main()
{
std::map<int,double> mymap;
int key = 666;

mymap.find(key);

if (auto finder = do_find(mymap, key))
{
// use finder.obj() somehow:
std::pair<int,double> id = finder.obj();
}
else
{
// deal with it
}
}

Feel free to modify it.

Victor
 

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

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,012
Latest member
RoxanneDzm

Latest Threads

Top