• Create Account

## compiler discrepancy: use of undefined type

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

9 replies to this topic

### #1e‍dd  Members

2109
Like
0Likes
Like

Posted 10 August 2012 - 02:59 PM

#include <iosfwd>

struct foo { };

std::ostream &operator<< (std::ostream &out, const foo &) { return out; }

void format(std::ostream &out, const foo &x) { out << x; }

int main()
{
return 0;
}


Comeau online and g++ 4.6 both accept this code without issue. Visual C++ 2010 complains:

P:\guff>cl /nologo /EHsc /W3 ostream_fwd.cpp /Feostream_fwd.exe
ostream_fwd.cpp
ostream_fwd.cpp(7) : error C2027: use of undefined type 'std::basic_ostream<_Elem,_Traits>'
with
[
_Elem=char,
_Traits=std::char_traits<char>
]


Who's correct? If someone could try this on the latest Visual C++ compiler, I'd be interested to see what it says/does.

### #2krippy2k8  Members

646
Like
0Likes
Like

Posted 10 August 2012 - 03:56 PM

VS2012 RC gives the same error. Clang also compiles without error. Based on that I would say that VS is probably wrong, but I think it's a bit of a grey area whether the compiler should want the definition of a type when evaluating operators for which there is an explicit external operator defined, so I would personally err on the side of them being right.

### #3ApochPiQ  Moderators

21389
Like
0Likes
Like

Posted 10 August 2012 - 04:05 PM

It wouldn't surprise me if this is one of many aspects of C++ that is left up to the implementers to clarify. Unfortunately I don't have the brainpower or patience to go standards-diving for the answer, so I'll just speculate uselessly :-P
Wielder of the Sacred Wands

### #4Ripiz  Members

538
Like
0Likes
Like

Posted 10 August 2012 - 04:05 PM

edd, are you sure you're not including ostream or other library by mistake? That library would fix this error.

According to MSDN and cpp.reference.com and even gcc, iosfwd contains only forward declaration, making me believe you're the one who made mistake.

Sources:
http://msdn.microsoft.com/en-us/library/1af12yty%28v=vs.110%29.aspx
http://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.1/group__s27__2__iosfwd.html

### #5krippy2k8  Members

646
Like
0Likes
Like

Posted 10 August 2012 - 04:34 PM

According to MSDN and cpp.reference.com and even gcc, iosfwd contains only forward declaration, making me believe you're the one who made mistake.

That's true, but his code doesn't really use anything that requires the definition of the class, so a forward declaration is all that would be necessary for the compiler to evaluate the expressions.

You can replace that code with this:
struct foo { };

class mynonexistentostream;

mynonexistentostream &operator<< (mynonexistentostream& out, const foo &) { return out; }

void format(mynonexistentostream& out, const foo &x) { out << x; }

int main()
{
return 0;
}


and the result is the same; an error on VS and no error on the other compilers, with no headers being included at all.

A compiler needs to evaluate any class member operators and namespace-scoped operators to determine which one to use, but in this case the namespace-scoped operator is clearly the best possible option, so a compiler would be able to evaluate things without having the class definition. Whether a compiler is actually required to do so per the standard I'm not sure about. There's a very good chance that it's not, and both may be technically compliant.

Edited by krippy2k8, 10 August 2012 - 04:36 PM.

### #6e‍dd  Members

2109
Like
0Likes
Like

Posted 10 August 2012 - 04:59 PM

According to MSDN and cpp.reference.com and even gcc, iosfwd contains only forward declaration,

That's entirely the gist of my inquiry.

Intuitively, I don't think that there's anything in the code that should require the definition, but the standard might require it.

making me believe you're the one who made mistake.

Can you phrase that in terms of standardese? I'll have a go myself on monday when I have my copy to hand.

If anybody can think of a way of tricking Visual C++ in to compiling this code, that would be handy (without #include <ostream>!)

Edited by e‍dd, 10 August 2012 - 05:02 PM.

### #7e‍dd  Members

2109
Like
0Likes
Like

Posted 10 August 2012 - 05:27 PM

From MSDN's page on C2027:

It is possible to declare a pointer to a declared but undefined type. But Visual C++ does not allow a reference to an undefined type.

I guess this supports the grey-area hypothesis.

### #8krippy2k8  Members

646
Like
0Likes
Like

Posted 10 August 2012 - 06:14 PM

Edit: nevermind, followup coming.

Edited by krippy2k8, 10 August 2012 - 06:33 PM.

### #9krippy2k8  Members

646
Like
3Likes
Like

Posted 10 August 2012 - 07:44 PM

Actually after further investigation, it appears that Visual Studio is patently wrong. The reason for the error is not because of operator resolution issues, it's because of an apparent compiler limitation that does not allow references to undefined types to be returned from a function if they are not assigned. C2027 says that references to undefined types are not allowed, but that is not the case; if their example code is changed to the following it compiles fine:

A& a = CreateA();

It just doesn't work if the return value is unassigned as in their example.

Per section 5.2.2 of the C++ standard, the result type of a function call that returns an lvalue reference is an lvalue, so an incomplete type should be fine.

Since the operator << returns a reference, and it is not being assigned, the same error is being invoked.

A workaround for your code could then be this:

void format(std::ostream &out, const foo &x) { std::ostream& t = out << x; }

which should compile fine.

Update: so, apparently the reason that it doesn't work in VS is because VS is unable to convert an undefined type to type void, and a function with the return value unassigned is equivalent to casting to type void, i.e.
(void)CreateA();

The C++ standard states that "Any expression can be explicitly converted to type cv void, in which case it becomes a discarded-value expression."

Therefore VS is wrong and the others are right.

Edited by krippy2k8, 10 August 2012 - 08:23 PM.

### #10e‍dd  Members

2109
Like
0Likes
Like

Posted 11 August 2012 - 04:06 AM

A workaround for your code could then be this:

void format(std::ostream &out, const foo &x) { std::ostream& t = out << x; }

which should compile fine.

Nice find! Thanks!

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.