This question already has answers here:
C++ auto keyword. Why is it magic?
(8 answers)
Closed 3 years ago.
I came across a curious line of code of the form:
// Given the following definitions:
class B;
B b;
// Line of interest:
auto a(b);
I thought it must be a typo, but after some experimentation found out that it works, and seems to always call the copy constructor of the type of b (even if you have other classes that can also have a matching constructor, and even if you additionally delete the copy constructor for the type of b).
I don't know the technical name of such a statement, so I'm not sure how to search for it in cppreference or StackOverflow. How does the compiler parse this type of statement in general, and where is it documented?
--
Re: duplicate marking. I don't see how they've addressed this construct. I already know auto uses template type deduction, that doesn't clarify anything in this case.
How is auto a(b); parsed in C++?
Depends on what b is. If b is a type, then this is a declaration of function with name a with deduced return type and a single argument of type b.
If b is not a type, then this defines a variable by the name a whose type is deduced from the initialiser.
where is it documented?
The authoritative documentation is the standard document. The standard sections [dcl.type.auto], [dcl.ambig.res], [dcl.fct], [dcl.init] should be relevant.
There are also websites that offer the documentation in (arguably) more approachable manner.
This should also be covered by recent (as in, anything since 2011) introductory C++ books.
and even if you additionally delete the copy constructor for the type of b
I doubt this. Create a mcve.
Related
This question already has answers here:
C++ auto keyword. Why is it magic?
(8 answers)
Closed 12 months ago.
In Java, Object takes the place of various class objects, but casting is needed. In the piece of code below, auto seems to be doing the same only that it does not need to be casted with a type variable.
It seems like a lazy (efficient?) way to progress through code. I might get accustomed to using auto instead of a specific type (in the example below, it would be 'int index'). There might be an occasion(s) where such incorporation would not be recommended.
piece of code:
vector<int> fCount(1001,0);
for(auto index : list)
{
++fCount[index];
}
Actually NO. Object in Java differs from auto in C++. In C++, auto keyword only can be applied to any type that can be deduced in compile-time, not run-time. In the code snippet you given, although the index is deduced to be an int, but if you try to use to use index in wherever context that the int cannot be used, compiler will complain.
auto is just a syntactic sugar that modern C++ offers, that you do not have to specify the type when compiler can deduce from the expression. Although you do not have to specify the type explicitly, compiler specifies it in implicit way. After the compiler deduced the type, you cannot use the variable as other type(if it cannot be implictly converted)
This question already has answers here:
What is the purpose of a declaration like int (x); or int (x) = 10;
(2 answers)
Why does C++ allow us to surround the variable name in parentheses when declaring a variable?
(2 answers)
Closed 5 years ago.
After watching Louis Brandy talk at CppCon 2017 I was shocked to discover that this code actually compiles:
#include <string>
int main() {
std::string(foo);
return 0;
}
And for some reason std::string(foo) it is identical to std::string foo i.e. declaring a variable. I find it absolutely counterintuitive and can't see any reason for C++ to work that way. I would expect this to give an error about undefined identifier foo.
It actually makes expressions like token1(token2) have even more possible interpretations than I previously thought.
So my question is: what is the reason for this horror? When is this rule actually necessary?
P.S. Sorry for the poorly worded title, please, feel free to change it!
Since this question is tagged language-lawyer, the direct answer is that, from [stmt.ambig]:
There is an ambiguity in the grammar involving expression-statements and declarations: An expression-statement with a function-style explicit type conversion as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a (. In those cases the statement is a declaration.
And, similarly, for functions, in [dcl.ambig.res]:
The ambiguity arising from the similarity between a function-style cast and a declaration mentioned in [stmt.ambig] can also occur in the context of a declaration. In that context, the choice is between a function declaration with a redundant set of parentheses around a parameter name and an object declaration with a function-style cast as the initializer. Just as for the ambiguities mentioned in [stmt.ambig], the resolution is to consider any construct that could possibly be a declaration a declaration.
Hence:
Why oh why is std::string("foo") so different from std::string(foo)
The former cannot be a declaration. The latter can be a declaration, with a redundant set of parentheses. Thus, the former isn't a declaration and the latter is.
The underlying issue is that, grammaticaly, declarators can start with a ( which could make it indistinguishable from a function-style explicit type conversion. Rather than come up with arbitrary complex rules to try to determine what the user meant, the language just picks one, and it's easy enough for the user to fix the code to actually do what he meant.
After reading this article I made a point that int () yields 0 because the temporary int is value initialized and not because int() calls the default constructor for int. (The article is flawed according to my understanding.)
I also said that primitive (built-in) types don't have constructors. The original author asked me to check Section $10.4.2 (TC++PL) which says
Built-in types also have default constructors ($6.2.8)
But I still think that the statement "C++ allows even built-in type (primitive types) to have default constructors." is flawed (as per C++03).
I think Bjarne in TC++PL has mixed up "constructor like notation i.e ()" with actual constructor call. Value initialization was not introduced at that time when Bjarne was writing the book, right? So is the text in TC++PL incorrect as per C++98 and C++03?
What do you guys think?
EDIT
I asked Bjarne personally (via mail) regarding the flawed text in TC++PL and this was his reply
I think you mix up "actual constructor calls" with conceptually having a constructor. Built-in types are considered to have constructors (whatever words the standard uses to describe their behavior).
Simple Answer: Technically No.
Long Answer:
No. But!
The syntax you use to initialize them makes them look like they are being constructed by a default constructor or a default copy constructor.
int x0(5); // Looks like a constructor. Behaves like one: x is initialized.
int x1{5};
int y0(); // Fail. Actually a function declaration.
// BUT
int y1{}; // So new syntax to allow for zero initialization
int z0 = int();// Looks like a constructor. Behaves like a constructor (0 init).
int z1 = int{};
int a0(b); // Again.
int a1{b};
So technically there are no constructors for basic-POD types. But for all intents and purposes they act just like they have a copy constructor and default constructor (when initialized with the braces).
If it looks like a duck and quacks like a duck, then its very duck like.
A constructor is a member function (constructors are fully specified in clause 12 of the C++ Standard, which covers special member functions like constructors and destructors).
A member function can only be defined for a class type (C++03 9.3/1 says "Functions declared in the definition of a class, excluding those declared with a friend specifier, are called member functions of that class").
So non-class types (including fundamental types, array types, reference types, pointer types, and enum types) do not have constructors.
I don't have a copy of The C++ Programming Language to read the context of the quote that "Built-in types also have default constructors," but I would guess that Stroustrup is either using the term "constructor" in a loose, non-technical sense, or the meaning of the term or the way in which it is used in the Standard changed between when the book was published and when the language was standardized. I'd guess the former is far more likely than the latter.
As others have pointed out, the Standard contradicts TC++PL in a few instances, often related to terminology. Bjarne Stroustrup himself summarizes the situation well:
(...)
However, [TC++PL] is not a reference manual or the standards text. If you need 100% precise and complete information you'll have to consult the text of the ISO C++ standard.
(...)
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
OK, I know this looks like a duplicate of Why do functions need to be declared before they are used? but it doesn't seem like existing answers fully address all the details.
I know that C++ was originally designed in the 80's so it could be translated in a single pass, because computers were slow. OK. But the most recent standard was published in 2011, so I don't see why C++ compilers can't do things now that require multiple passes. It would still hurt performance, yes, but only if it actually became necessary. So the following would still only require a single pass:
void foo();
int main() { foo(); }
void foo() {}
whereas for the following, the compiler could make two (and be slower), because it doesn't know whether foo is a function or a type until it sees the declaration below:
int main() { foo(); }
void foo() {}
and if you tried to use a function without declaring it first, and the declaration is not in the current translation unit at all, then it would be an error. But if it's in the same translation unit then the compiler could just make additional passes.
My colleague argues that such a feature would save a lot of developer time, and would avoid issues with the declaration and definition not being matched. And I'm sure this has been proposed many times over and rejected every time. What is the actual reasoning behind rejecting it, i.e., the committee's rationale?
Template parsing
Consider the following line of code:
a < b , c > d;
How would you parse this? There are actually two ways, depending on what a, b, c and d are. Firstly, a variable declaration
a<b,c> d;
^^^^^^ ^
Type Var
in the case that a is a known template type, b and c are other known types. Secondly,
a<b , c<d ;
^^^ ^^^
boolean expressions
in the case that a, b, c and d are all variables of some sort.
The vexing parse
Or here another one:
a b(c); // is 'b' a function or a variable?
This could be a function declaration (a function with return type a and argument type c) or a variable definition (whose type is a and whose constructor argument is c).
Conclusion
There's a lot of stuff like that, unfortunately. I'm not sure, if it would be impossible to write a compiler that can deal with that kind of stuff, but it would at least be very hard to write one. Compilation times are a serious issue in C++ already. This would only make it worse. Also: It is good practice to only use what you have defined or declared already, even in other languages.
Constraints of the committee
Even if it would be reasonably possible to implement this feature, it would kill backwards compatibility. Function overloading resolution only takes prior declarations into account and the interpretation of function calls may change depending on the place a function call is written. That's the way C++ is put together. Now, the C++ standards committee is big on back-wards compatibility. In particular: They do not want to break any existing code (and rightly so). Your proposal would surely break existing code which is a no-go for the language designers.
The current answer is because it would be unparseable.
Consider two-phase name lookup for templates, and in particular the need for typename. In templates, type-dependent names may not have been declared yet. To be able to parse them, we absolutely need typename. Without that, parsing would grind to a halt and we can't reliably proceed, so we couldn't even provide the type needed to fix the parsing problem. It's a chicken and egg problem: If we need to have parsed line 10 to parse line 5, line 10 will never be parsed because we break at line 5. typename helps us get past line 5 so we can learn the actual type on line 10.
Here, we'd have a similar problem. Consider this code under your assumptions:
struct Foo { };
int bar () { return Foo(); }
int Foo () { return 42; }
To parse this code, we need to know whether Foo denotes a type or function.
This question already has answers here:
Why does c++ pointer * associate to the variable declared, not the type?
(3 answers)
Closed 9 years ago.
int* p1, p2;
According to the C++ standard, p1 is a pointer yet p2 is not.
I just wonder why the C++ standard doesn't also define p2 as a pointer?
I think it is reasonable to do so. Because:
C++ is a strong-typing language. That is to say, given any type T, the statement T t1, t2; always guarantees t1 and t2 have the same type.
However, the fact that p1 and p2 don't have the same type breaks the rule, and seems counter-intuitive.
So, my question is: What's the rationale to make such a counter-intuitive rule as is? Just for backward compatibility?
int is the base type, * or & are prefix specifiers which are also called declarator operators. It means that * operates on the variable after it. And it is not a modifier for int. I think that is why.
The simple answer that won't help you much is that this is done for backwards compatibility with C, that has exactly the same syntax to define variables. The rationale for that design would have to come from the creators of C, and I don't really know it.
What I do know is that most coding guidelines I have used in different companies prohibited the definition of multiple variables in the same statement, and once you avoid that, everything becomes simple to read an maintain. The syntax for declarations in C and C++ is not really one of their strengths, but it is what it is.