11

It is possible to define and copy-initialize a variable inside the condition of an if statement :

if(int i = 17) { ... }

This also works with user-defined types, given that they overload operator bool :

if(Foo f = 42)      { ... }
if(Foo f = Foo(43)) { ... }

Why can't I use direct-initialization, like the following ?

if(Foo f(51)) { ... }

GCC emits error: expected primary-expression before 'f'.

Live on Coliru

Is there a reason other than "because the grammar says so" ? And how can I work around it ?

I'm working with VC++03, where Foo :

  • is a RAII-sensitive object, for which I took care not to define a copy constructor
  • is a template taking arguments from the user
  • has a two-parameters constructor

... so I'd rather avoid copying it or repeating its type.

Note : Although my actual problem is with C++03, I'm (academically) interested about answers in C++11.

Quentin
  • 62,093
  • 7
  • 131
  • 191
  • Related to [Can a variable be defined only in the scope of an if-statement, similar to how it's often done for for-loops?](http://stackoverflow.com/q/24017216/1708801) – Shafik Yaghmour Jul 02 '15 at 13:26
  • Why do you think the declaration `Foo f = 42` implies a copy/move? Shouldn't copy elision work? – Columbo Jul 02 '15 at 14:47
  • @Columbo AFAIK copy elision is an optimization that maus or may not be performed, but even if it's not the object needs a copy constructor, which I've disabled to avoid `auto_ptr`-like evil. In the end I worked around the problem by passing an `std::pair`. – Quentin Jul 02 '15 at 14:55
  • How did passing an `std::pair` work around the problem? You still need a copy constructor if it's copy initialization from a different type. – bogdan Jul 02 '15 at 15:09
  • @bogdan Indeed. Now I'm wondering why it works. – Quentin Jul 02 '15 at 15:12
  • @Quentin Hmm, I didn't know you disabled the copy ctor. Nevermind then. – Columbo Jul 02 '15 at 15:18
  • @Quentin I tried it on GCC 5.1.0, `-Wall -Wextra -std=c++98 -pedantic`, with a toy class with a private copy constructor and it didn't work on my side. – bogdan Jul 02 '15 at 15:19
  • @bogdan Doesn't surprise me (MSVC 2008 here). Well I'll be happy it works and carry on :) – Quentin Jul 02 '15 at 15:23
  • @Quentin Looks like it's a [known bug](https://connect.microsoft.com/VisualStudio/feedback/details/795199/copy-initialization-bug) in MSVC. Even the latest 2015 version accepts the code. Sad, really. – bogdan Jul 02 '15 at 17:36

3 Answers3

11

In C++03, one could solely use the copy-initialization syntax:

selection-statement:
       if ( condition ) statement
        […]

condition:
       expression
       type-specifier-seq declarator = assignment-expression

Since C++11, list-initialization was added:

condition:
        expression
       attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause
       attribute-specifier-seqopt decl-specifier-seq declarator braced-init-list

The syntax of direct-initialization, i.e. Foo f(…), was presumably avoided for the same reason it was disallowed for non-static data member initializers: Ambiguities, in particular the "most vexing parse".

Columbo
  • 60,038
  • 8
  • 155
  • 203
2

Because the C++03 standard only allows assignment initialisation inside conditions:

condition:
    expression
    type-specifier-seq declarator = assignment-expression
Alexander Balabin
  • 2,055
  • 11
  • 13
2

Given your restrictions, I believe in C++03 your only option is to declare the variable outside the if statement, adding braces for scoping:

{
    Foo f(51, 52);
    if (f) {
        //...
    }
}

In C++11 you could exploit braced initialization syntax:

if (Foo f{51, 52}) {
    //...
}
Anton Savin
  • 40,838
  • 8
  • 54
  • 90