9

sorry for the question title but I didn't know a correct title for my problem. I have the following code example:

struct test {
    test(int a) {
    }
};

int main() {
    test(1);
    return 0;
 }

The above example code works. Now i do (in my understanding) the same a bit differently:

struct test {
     test(int a) {
     }
};

int main() {
    int a = 0;
    test(a);
    return 0;
}

When I compile this I get the following error:

error: redefinition of 'a' with a different type: 'test' vs 'int'

But in my opinion it gets really strange when I try this:

struct test {
    test(int a) {
    }
};

int main() {
    int a = 0;
    test((int)a);
    return 0;
}

the above example works again and really confuses me since I don't see the difference (except casting an int to an int). Can anyone explain what's going on? Thank you in advance.

roohan
  • 731
  • 3
  • 8
  • 15
  • This is called *most vexing parse*. Clang is being [more helpful](https://gcc.godbolt.org/z/YfD5Hu) than GCC here: `warning: parentheses were disambiguated as redundant parentheses around declaration of variable named 'a'` `note: add enclosing parentheses to perform a function-style cast` – HolyBlackCat Nov 11 '19 at 09:38

4 Answers4

5

You forgot to give your test variable a name, causing test(a); to be a declaration of a variable named a of type test.

In the other cases, since test(1) and test((int)a) cannot be declarations, but must be some kind of call, your compiler will treat that as constructing a temporary object of type test without a name.

Max Vollmer
  • 8,412
  • 9
  • 28
  • 43
4

This is really tricky:

test(1);

This is a construction of test with argument 1.

int a = 1;
test(a);

The compiler reads this as test a; (instance of test named a – with default construction). That test doesn't even provide a default constructor isn't considered by compiler at this point.

The fix (found by OP):

int a = 1;
test((int)a);

Now, the compiler is explicitly told to read a as expression (but not as identifier).

Scheff's Cat
  • 19,528
  • 6
  • 28
  • 56
3

The syntax of defining variables in C++ is kind of quirky...

When you do

test(1);

you create a temporary object of the test structure. This object will be destructed immediately.

But when you do

test(a);

you don't create a temporary test object, you actually define a variable named a. It's equivalent to

test a;

You can solve this problem by using curly-braces

test{a};

Or by using an explicit expression for the "argument" (like you do with your cast), as such can't be used as variable names. In similar situation where you need to disambiguate between variables and expressions it's common to use the unary + as in

test(+a);
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
2

In ISO C++ Standard (ISO/IEC 14882) 2003, at section 3.2:

In any translation unit, a template, type, function, or object can have no more than one definition.

Please note that The One Definition Rule (ODR) is an important concept in the C++ programming language.

If you want to have many functions with same name (and different signatures, of course), function overloading is a feature which you want.

Kevin
  • 16,549
  • 8
  • 60
  • 74
ne3suszr
  • 83
  • 7