Declaration and declaration with definition. Why is this not allowed? - c++

I wonder, why it is not allowed to write:
struct foo {
void bar(); // declaration
void bar(){std::cout << "moo" << std::endl;} // declaration + definition
};
The function is declared twice (I thought this is ok) and defined once. However, my compiler complains about:
decldef.cxx:7:10: error: 'void foo::bar()' cannot be overloaded
Why is it not allowed?
Why does my compiler (g++ 4.7.2) interpret this as overloading?
PS: I know how to write it "the correct way", but I just would like to know, why the above is wrong.

From §9.3
Except for member function definitions that appear
outside of a class definition, and except for explicit specializations of member functions of class templates
and member function templates (14.7) appearing outside of the class definition, a member function shall not
be redeclared.
In addition, in this case the statements may also fall foul of:
A member function may be defined (8.4) in its class definition, in which case it is an inline member function
(7.1.2), or it may be defined outside of its class definition if it has already been declared but not defined
in its class definition.
As the first declaration does not declare the function to be inline. The second definition implicitly does.
However, that one on reflection seems less convincing.

The function is declared twice (I thought this is ok) and defined once.
This is independent of whether or not you define the function the second time around. The point is that you are declaring the function twice, and that is not OK.
This does not compile either, with the same error message:
struct foo {
void bar();
void bar();
};
You may not re-declare the same function with the same parameter list inside the class definition:
'void foo::bar()' cannot be overloaded with 'void foo::bar()'.

Related

Virtual functions, class templates overriding them and incomplete types

Let's consider the following code snippet (spread across several files):
Base.h:
#include <iostream>
class Base
{
public:
virtual void foo () = 0;
};
template <class D>
class BaseImpl : public Base
{
public:
BaseImpl () : d (new D ()) {}
virtual ~BaseImpl () { delete d; }
void foo () override;
private:
D * d;
};
template <class D>
void BaseImpl <D>::foo ()
{
std::cout << d->value << std::endl;
}
Derived.h:
#include "Base.h"
struct Data;
class Derived : public BaseImpl <Data>
{
public:
Derived ();
~Derived ();
};
Derived.cpp:
#include "Derived.h"
struct Data
{
int value = 123;
};
Derived::Derived () {}
Derived::~Derived () {}
main.cpp:
#include "Derived.h"
int main ()
{
Derived d;
d.foo (); // [1] error
((Base *) & d)->foo (); // [2] fine
}
This example produces a compiler error on CLang (Apple LLVM version 10.0.0 (clang-1000.11.45.5) at line [1] as following:
g++ -c -std=c++11 main.cpp -o main.o
In file included from main.cpp:1:
In file included from ./Derived.h:1:
./Base.h:22:17: error: member access into incomplete type 'Data'
std::cout << d->value << std::endl;
^
main.cpp:7:5: note: in instantiation of member function 'BaseImpl<Data>::foo' requested here
d.foo (); // [1]
^
./Derived.h:3:8: note: forward declaration of 'Data'
struct Data;
^
1 error generated.
A similar error is generated by gcc 4.9.2:
g++ -c -std=c++11 main.cpp -o main.o
In file included from Derived.h:1:0,
from main.cpp:1:
Base.h: In instantiation of 'void BaseImpl<D>::foo() [with D = Data]':
main.cpp:7:10: required from here
Base.h:22:13: error: invalid use of incomplete type 'struct Data'
std::cout << d->value << std::endl;
^
In file included from main.cpp:1:0:
Derived.h:3:8: error: forward declaration of 'struct Data'
struct Data;
^
Interesting enough, if line [1] is commented out, everything builds (and works) fine and line [2] doesn't produce any compiler errors. What is the reason for this discrepancy?
The error at [1] expectedly goes away if the forward declaration of Data in Derived.h is replaced with its full definition from Derived.cpp but the intention is to make it hidden from users of Derived because it is implementation detail (see also below).
For those curious (and familiar with Qt), in real life Base is QAbstractItemModel, BaseImpl is a class template whose purpose is to provide real storage for model items and implement QAbstractItemModel (pure) virtual functions. Derived is merely an alias for BaseImpl implementing a particular data model and Data is what is used internally by this model to store each item's data so it should be separate from Derived and hidden from code using the final model class.
The example program is ill-formed.
To start with, the definition of any template is checked for valid syntax like all other code, but a C++ implementation is not required to check the semantics of any parts that depend on a template parameter unless/until that template is instantiated. (An implementation may report a semantic error even without any instantiations if there are no possible template arguments that would make a specialization valid.)
So the program is fine if the translation unit resulting from main.cpp does not instantiate the function template specialization BaseImpl<Data>::foo(). But when exactly is this template specialization instantiated? [temp.inst]/3 says:
Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist or if the existence of the definition of the member affects the semantics of the program.
The main requirement that a definition exists comes from the ODR rule, [basic.def.odr]/10:
Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program outside of a discarded statement; no diagnostic required.... An inline function or variable shall be defined in every translation unit in which it is odr-used outside of a discarded statement.
Here it doesn't matter whether we say the specialization BaseImpl<Data>::foo() is "inline" or not. Both flavors of the ODR rule end up saying that if the specialization is odr-used, then it must be defined (in some way or another), which means the specialization is implicitly instantiated.
There are different definitions of the technical term "odr-use" for different sorts of entities (and sometimes those definitions overlap). Quoting a bit more than necessary from [basic.def.odr]/5-8 to make a point:
A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless....
A structured binding is odr-used if it appears as a potentially-evaluated expression.
*this is odr-used if this appears as a potentially-evaluated expression (including as the result of the implicit transformation in the body of a non-static member function).
A virtual member function is odr-used if it is not pure. A function is odr-used if it is named by a potentially-evaluated expression. A non-placement allocation or deallocation function for a class is odr-used by the definition of a constructor of that class. A non-placement deallocation function for a class is odr-used by the definition of the destructor of that class, or by being selected by the lookup at the point of definition of a virtual destructor.
An assignment operator function in a class is odr-used by an implicitly-defined copy-assignment or move-assignment function for another class as specified in [class.copy.assign]. A constructor for a class is odr-used as specified in [dcl.init]. A destructor for a class is odr-used if it is potentially invoked.
Note all of these definitions for "odr-used" associate the property to some specific expression or definition, except the one saying a virtual function that is not pure is odr-used just by existing. So in most cases, implicit instantiation happens because of these specific other expressions and definitions which require the template specialization. What this means in terms of instantiating a virtual function is somewhat clarified in [temp.inst]/10 and [temp.point]/5:
It is unspecified whether or not an implementation implicitly instantiates a virtual member function of a class template if the virtual member function would not otherwise be instantiated.
If a virtual function is implicitly instantiated, its point of instantiation is immediately following the point of instantiation of its enclosing class template specialization.
So if your main.cpp never mentioned foo at all, but it still required the instantiation of class BaseImpl<Data> while Data is still an incomplete type, it would be unspecified whether or not the program is valid! So even that's probably not a good idea.
Incidentally though, this is why the translation unit from Derived.cpp is allowed to instantiate BaseImpl<Data>::foo(). And g++, along with most compilers that use the common "vtable" strategy for virtual functions, will instantiate any needed class template members which are the final overrides for a class whenever any constructor for that class is (explicitly or implicitly) defined, since it needs to build a vtable which includes those functions so the constructor can set the class object's internal vptr to point at the vtable.
But I said at the start it's ill-formed, because of the other piece implied by "would not otherwise be instantiated". The other sentence which could imply BaseImpl<Data>::foo() is odr-used was "A function is odr-used if it is named by a potentially-evaluated expression". Backing up shortly before that quote, we find that "function named by an expression" is also a technical definition, in [basic.def.odr]/3:
A function is named by an expression as follows:
A function whose name appears in an expression is named by that expression if it is the unique lookup result or the selected member of a set of overloaded functions ([basic.lookup], [over.match], [over.over]), unless it is a pure virtual function and either its name is not explicitly qualified or the expression forms a pointer to member ([expr.unary.op]).
...
Now the expression d.foo() does a lookup for a member foo in Derived, and the unique result is BaseImpl<Data>::foo(). Since it's not pure virtual, d.foo() names BaseImpl<Data>::foo(). The expression ((Base *) & d)->foo() does a lookup for a member foo in Base, and the unique result is Base::foo(). Since Base::foo() is pure virtual and the name foo is unqualified in the expression, ((Base *) & d)->foo() does not name any function.
I'm sure you know those two expressions (if the program were changed to be valid) would actually call the same function. But the way polymorphism is described in the C++ Standard is that the function which is named is not always the same as the function which is called. This distinction is also important for other reasons - like the member access checks apply to the named function, not the called function, and the default arguments associated with declarations of the named function, not the called function, are available for use. It just happens that here's another tricky difference that comes up depending on the actual function named.
Anyway, to tie it up, the expression d.foo() in main.cpp odr-uses BaseImpl<Data>::foo(), which means an implicit instantation of BaseImpl<Data>::foo(). Since d points at an object of incomplete class type Data, the expression d->value in the definition of this instantiated specialization is ill-formed.

Difference between prototype declaration and forward declaration?

So I have this code:
class xx
{
int getnum(); //Is this a forward declaration or a prototype declaration and why?
};
int xx::getnum()
{
return 1+3;
}
So the question has already been commented in the code but:
Is int getnum(); a forward declaration or a prototype declaration and why?
Neither the term "forward declaration" nor "prototype declaration" are defined in the C++ standard, so very strictly speaking, it's neither. It is simply a declaration. If you want to be more specific, you could call it a non-defining declaration, or "a declaration which is not a definition."
When the words "forward declaration" are used in the standard, they are used to refer to declarations which declare, but do not define, the thing (function or class) they declare. Following this usage, int getnum() is therefore a forward declaration.
"Prototype declaration" of a function is used even less in the standard(1), and mostly when talking about [in]compatibility with C. However, when used, it refers to the exact same concept as a forward declaration of that function. Going by this, you could also call int getnum(); a prototype declaration.
To summarise, the terms "forward declaration" and "prototype declaration" have no formal definition, but from the way they are normally used and understood, int getnum(); can be described as either.
(1) However, a similar term "function prototype scope" is defined in the standard (C++17 N4659 [basic.scope.proto] 6.3.4/1). It establishes the scope of function parameter names in a non-defining function declaration, and it's the closest enclosing function declarator.
C++ only allows full prototype declarations of functions, unlike C in which something like int getnum(); could be a forward declaration of something like int getnum(int);
C.1.7 Clause 8: declarators [diff.decl]
8.3.5
Change: In C ++ , a function declared with an empty parameter list takes no arguments. In C, an empty
parameter list means that the number and type of the function arguments are unknown.
Example:
int f(); // means int f(void) in C ++, int f( unknown ) in C
Rationale: This is to avoid erroneous function calls (i.e., function calls with the wrong number or type of
arguments).
Effect on original feature: Change to semantics of well-defined feature. This feature was marked as
“obsolescent” in C.
Difficulty of converting: Syntactic transformation. The function declarations using C incomplete declaration style must be completed to become full prototype declarations. A program may need to be updated further if different calls to the same (non-prototype) function have different numbers of arguments or if the
type of corresponding arguments differed.
A forward declaration is a declaration of an identifier (denoting an entity such as a type, a variable, a constant, or a function) for which the programmer has not yet given a complete definition.
On the other hand a prototype refers to a function not an identifier.
Hope the following clear things out for you!
int getnum(); // Function prototype. You have not yet implemented the body of getnum() function, thus its a forward delcaration.
class RandomClass; // Forward declaration of RandomClass. You have not yet implemented this class but you need it for the rest of your code.
class xx{
RandomClass *foo; // Our need of having a member like that, made us make a forward declaration of the class RandomClass, above class xx
void BarFunction(); // Function Prototype!
};
int getnum(){ //This is the simply the body of your prototype above. Has nothing to do with the classes
return 1+3;
}
void BarFUnction(){
cout << "foo-bar\n" ;
}
Forward declaration is a type of declaration where you specify an Identifier for a Variable, Constant, Type or a Function without giving it's implementation. it actually tells the compiler about an entity with some meta data like name, size etc.
On the other hand, by prototype declaration for a Function means the declaration of a Function with a name and type signature without specifying the function body. So it's only for the function concept, not for variables, constants or types. And so forward declaration can be regarded as a superset of prototype declaration.
For the above example, according to definitions, it's both forward declaration and prototype declaration. Hopefully I am not wrong.

Using "using" twice interpreted differently by different compilers

Consider the following code:
struct A {
int propose();
};
struct A1 : A {
int propose(int);
using A::propose;
};
struct B1 : A1 {
protected:
using A1::propose;
public:
using A::propose;
};
int main() {
B1().propose();
}
Let's compile this: g++ -std=c++11 main.cpp.
I'm getting the following compiler error using GNU 4.8.1:
main.cpp: In function 'int main()':
main.cpp:2:9: error: 'int A::propose()' is inaccessible
int propose();
^
main.cpp:18:18: error: within this context
B1().propose();
However, this code compiles in AppleClang 6.0.0.6000056.
I understand that there is no need for the using in B1, (in my code was necessary, but I had 1 using too much by mistake). In any case, why Clang compiles it? Is this expected?
In [namespace.udecl], we have:
When a using-declaration brings names from a base class into a derived class scope, member functions and
member function templates in the derived class override and/or hide member functions and member function
templates with the same name, parameter-type-list (8.3.5), cv-qualification, and ref-qualifier (if any) in a
base class (rather than conflicting).
The standard explicitly says that names brought in will not conflict with names in a base class. But it doesn't say anything about bringing in conflicting names.
The section also says:
A using-declaration is a declaration and can therefore be used repeatedly where (and only where) multiple
declarations are allowed. [ Example:
struct B {
int i;
};
struct X : B {
using B::i;
using B::i; // error: double member declaration
};
—end example ]
And interestingly, in the following example it's GCC that happily compiles it (and prints A) while Clang allows the construction of a C but rejects the call to foo as ambiguous:
struct A {
void foo() { std::cout << "A\n"; }
};
struct B {
void foo() { std::cout << "B\n"; }
};
struct C : A, B {
using A::foo;
using B::foo;
};
int main()
{
C{}.foo();
return 0;
}
So the short answer is - I suspect this is underspecified in the standard and that both compilers are doing acceptable things. I would just avoid writing this sort of code for general sanity.
The declaration is legal.
Calling it is legal and should work anywhere, and it can only be called from the class and derived classes, and it can be called from within any class. You'll note that this makes little sense.
There are no rules that ban that construct in declarations (importing the name twice from two different base classes with the same signature), and it is even used in "real" code where the derived class goes and hides the name after they are imported.
If you don't hide it, you are in the strange situation where the same function A::propose is both protected and public at the same time, as it is named twice (legally) in the same scope with different access control. This is ... unusual.
If you are within a class, a sub-clause says you can use it:
[class.access.base]/5.1
A member m is accessible at the point R when named in class N if — (5.1) m as a member of N is public
and propose is clearly public. (it is also protected but we don't have to keep reading for that case!)
Elsewhere, we have a contradiction. You are told you can use it everywhere without restriction [class.access]/1(3). And you are told that you can only use it in certain circumstances [class.access]/1(2).
I am uncertain how to resolve that ambiguity.
The rest of the logic train:
In [namespace.udecl]/10 we have:
A using-declaration is a declaration and can therefore be used repeatedly where (and only where) multiple declarations are allowed.
And [namespace.udecl]/13:
Since a using-declaration is a declaration, the restrictions on declarations of the same name in the same declarative region
so each of those using X::propose; are declarations.
[basic.scope] has no applicable restrictions on two functions of the same name in a scope, other than [basic.scope.class]/1(3) which states that if reordering of declarations changes the program, the program is ill-formed. So we cannot say that the later one wins.
Two declarations of member functions in the same scope are legal under [basic.scope]. However, under [over], there are restrictions on two member functions with the same name.
[over]/1 states:
When two or more different declarations are specified for a single name in the same scope, that name is said to be overloaded
And there are some restrictions on overloading. This is what usually prevents
struct foo {
int method();
int method();
};
from being legal. However:
[over.load]/1 states:
Not all function declarations can be overloaded. Those that cannot be overloaded are specified here. A program is ill-formed if it contains two such non-overloadable declarations in the same scope. [Note: This
restriction applies to explicit declarations in a scope, and between such declarations and declarations made through a using-declaration (7.3.3). It does not apply to sets of functions fabricated as a result of name lookup (e.g., because of using-directives) or overload resolution (e.g., for operator functions). —end note
the note explicitly permits symbols introduced via two using-declarations from being considered by the overloading restrictions! The rules only apply to two explicit declarations within the scope, or between an explicit declaration within the scope and a using declaration.
There are zero restrictions on two using-declarations. They can have the same name, and their signatures can conflict as much as you'd like.
This is useful, because usually you can go and then hide their declaration (with a declaration in the derived class), and nothing goes wrong [namespace.udecl]/15:
When a using-declaration brings names from a base class into a derived class scope, member functions and member function templates in the derived class override and/or hide member functions and member function templates with the same name, parameter-type-list (8.3.5), cv-qualification, and ref-qualifier (if any) in a base class (rather than conflicting).
However, this is not done here. We then call the method. Overload resolution occurs.
See [namespace.udecl]/16:
For the purpose of overload resolution, the functions which are introduced by a
using-declaration into a derived class will be treated as though they were members of the derived class. In particular, the implicit this parameter shall be treated as if it were a pointer to the derived class rather than to the base class. This has no effect on the type of the function, and in all other respects the function remains a member of
the base class.
So we have to treat them as if they are members of the derived class for the purpose of overload resolution. But there are still 3 declarations here:
protected:
int A::propose(); // X
int A1::propose(int); // Y
public:
int A::propose(); // Z
Thus the call to B1().propose() considers all 3 declarations. Both X and Z are equal. They, however, refer to the same function, and overload resolution states there is an ambiguity if two different functions are selected. So the result is not ambiguous. There may be access control violations, or not, depending on how you read the standard.
[over.match]/3
If a best viable function exists and is unique, overload resolution succeeds and produces it as the result. Otherwise overload resolution fails and the invocation is ill-formed. When overload resolution succeeds, and the best viable function is not accessible (Clause 11) in the context in which it is used, the program is ill-formed.

Unusual scope resolution operator

While refactoring some C++ code today I got some code which boils down to the following
class x
{
public:
void x::y();
};
Does the x:: scope resolution operator do anything here, is it a bug, or is it something else. My best guess is that it is an artefact left over by some autocomplete but I'm curious to know if I'm missing anything. Compiler in use is VS2010 SP1.
It's a bug, and most compilers will reject it. For example, GCC says
prog.cpp:4:10: error: extra qualification ‘x::’ on member ‘y’ [-fpermissive]
void x::y();
^
The redundant qualifier is disallowed by C++11 8.3/1:
A declarator-id shall not be qualified except for the definition of a member function or static data member outside of its class, the definition or explicit instantiation of a function or variable member of a namespace outside of its namespace, or the definition of an explicit specialization outside of its namespace, or the declaration of a friend function that is a member of another class or namespace.
with none of those exceptions applying to a member declaration inside its class.

Why VS 2008 compile with no warning with an erroneous template logic?

I have a simple template example that is as follow:
template<class T> class A {
friend int f(T);
}
int main(){
A<int> a;
return 0;
}
That code compile and execute without warning in VS2008 (except for the unused variable). I believe there should be a problem since we obtain many versions of a non-template function in the same class with only one definition. Did I miss something?
Why should this code produce an error? For every T you instantiate A with, a new function will be declared and friended. There will never be two identical functions, since you can't instantiate a template twice for the same type (you will just reuse the old instantiation).
Also, even if it was somehow possible to generate two equal declarations, there would be no ambiguity, since the functions are first declared inside the class. As such, they can never be found by anything other than argument dependant lookup. (Basically, those functions are useless as they cannot be called)
§7.3.1.2 [namespace.memdef] p3
[...] If a friend declaration in a nonlocal class first declares a class or function the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by unqualified lookup or by qualified lookup until a matching declaration is provided in that namespace scope (either before or after the class definition granting friendship). [...]
Also, see this.
According to the C++ standard, the degree of syntax checking for unused template functions is up to the implementation. The compiler does not do any semantic checking—for example, symbols are not looked up.