3

c++ accepts:

if(int a=1)
{
    //...
}

For learning purposes, I have written a simple lock mechanism class:

class SimpleLock
{
public:
    class Token
    {
    public:
        friend class SimpleLock;
        Token(SimpleLock & lock) : lock(lock), locked(!lock.locked.exchange(true)) { }
        ~Token() { if(locked) lock.locked.store(false); }
        operator bool() const { return locked; }

    private:
        SimpleLock & lock;
        const bool locked;
    };

    SimpleLock() : locked(false) { }

private:
    std::atomic_bool locked;
};

allowing me to do:

SimpleLock::Token t(lock);

if(t) //Token has an operator bool() overload
{
    //...
}

Why doesn't the following compile?

if(SimpleLock::Token t(lock))
{
    //...
}

Compiler error:

expected primary-expression before 't'

Online code link : http://goo.gl/Knrmw7

galinette
  • 8,896
  • 2
  • 36
  • 87
  • I'm pretty sure I've seen this asked before. – crashmstr Feb 15 '16 at 13:35
  • 1
    "*Why doesn't the following compile?*" Typically, the compiler tells you. Copy the message to your question. – eerorika Feb 15 '16 at 13:41
  • 2
    What does the compiler say? – Bo Persson Feb 15 '16 at 13:41
  • 1
    Related: [what's wrong with declaring a variable inside if's condition?](http://stackoverflow.com/questions/8961478/whats-wrong-with-declaring-a-variable-inside-ifs-condition) – crashmstr Feb 15 '16 at 13:43
  • 3
    @galinette I would probably have upvoted if it had a [mcve]. I do however not feel like writing code to find out if the question is even valid in the first place. – Baum mit Augen Feb 15 '16 at 13:47
  • Does `if(SimpleLock::Token t{lock})` (note the braces) work? – vsoftco Feb 15 '16 at 13:50
  • @BaummitAugen : done! – galinette Feb 15 '16 at 13:55
  • 1
    @galinette Close enough, have the upvote. For education purposes: A [real mcve](http://coliru.stacked-crooked.com/a/ecb354450d25f1f7) including the error message. – Baum mit Augen Feb 15 '16 at 14:00
  • @BaummitAugen now with the online compiler link... – galinette Feb 15 '16 at 14:12
  • 1
    @galinette As I said, the question was fine and the online compiler link does certainly not hurt, but what I tried to say is: a) Your example can be simplified significantly, the problem has nothing to do with the lock stuff b) I would like to be able to copy-paste and compile the mcve directly from the question and c) I would like to see the exact compiler error in the question. But again, your question is ok as is. – Baum mit Augen Feb 15 '16 at 14:34

2 Answers2

10

It doesn't compile because that form of initialization is not allowed in an if condition. This is just down to the syntactic forms which the standard says are valid.

You can either use the copy-initialization form or a braced-init-list:

if(SimpleLock::Token t = SimpleLock::Token(lock))
{
    //...
}

if(SimpleLock::Token t{lock})
{
    //...
}

This is specified in [stmt.select]/1 (N3337):

condition:

  • expression

  • attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause

  • attribute-specifier-seqopt decl-specifier-seq declarator braced-init-list

Community
  • 1
  • 1
TartanLlama
  • 63,752
  • 13
  • 157
  • 193
3

From http://en.cppreference.com/w/cpp/language/if

Syntax is if ( condition )

with condition is one of:

  • expression which is contextually convertible to bool
  • declaration of a single non-array variable with a brace-or-equals initializer.

We use the second bullet here, so

You have to use syntax with =:

if (SimpleLock::Token t = SimpleLock::Token(lock))
{
    //...
}

Demo

or construct your object with {} (instead of ())

if (SimpleLock::Token t{lock})
{
    //...
}

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • 1
    Likely because the copy operator returns something, not the constructor – galinette Feb 15 '16 at 13:46
  • Thanks, deleted my answer. This looks ok. BTW, in C++11, it looks like `if(SimpleLock::Token t{lock})` works. Cannot see why this is some vexing parse though... – vsoftco Feb 15 '16 at 13:46
  • This means I need a copy operator I suppose... My Token class is currently not copiable but I could implement a move assignment operator – galinette Feb 15 '16 at 13:48
  • 1
    @galinette: that use copy/move constructor, not assignment. – Jarod42 Feb 15 '16 at 13:48
  • vsoftco : hey, the bracket syntax works!!! Thats really the dark side of C++... Could someone elaborate an answer about this? – galinette Feb 15 '16 at 13:50
  • 1
    I would say `t(lock)` is not accepted due to parsing (like the most-vexing parse). – Jarod42 Feb 15 '16 at 13:52
  • @galinette Follow up question: http://stackoverflow.com/q/35411163/3093378. I don't think there should be any vexing parse here, although from the error it looks like there is, but don't know why. – vsoftco Feb 15 '16 at 13:54