Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Compile error

57 views
Skip to first unread message

ailynka...@gmail.com

unread,
Feb 11, 2019, 12:07:54 AM2/11/19
to
Hello friends.
I struggle to understand why this code doesn't compile - https://wandbox.org/permlink/BcFlcQTidpCg0lsJ

I tried gcc and ms vc++. They both have very similar errors.

What is strange that if we move friend expression before declaring any class members then code compiles fine. Or we can remove member operator + then it compiles too.

Alf P. Steinbach

unread,
Feb 11, 2019, 4:27:55 AM2/11/19
to
On 11.02.2019 06:07, ailynka...@gmail.com wrote:
> Hello friends.
> I struggle to understand why this code doesn't compile - https://wandbox.org/permlink/BcFlcQTidpCg0lsJ

You should put the code /in the question/.


------------------------------------------------------------------------------------------------
#include <iostream>

template<typename T>
class Test;

template<typename T>
Test<T> operator + (const Test<T>& lhs, const Test<T>& rhs);

template<typename T>
class Test
{
// this "friend" compiles
//friend Test<T> operator + <T> (const Test<T>& lhs, const Test<T>& rhs);
public:
explicit Test(T value)
: m_value(value)
{
}

// we comment this operator then it compiles
Test operator + (T value)
{
return Test(m_value + value);
}

private:
// this "friend" doesn't compile
friend Test<T> operator + <T> (const Test<T>& lhs, const Test<T>& rhs);
// this "friend" compiles
//friend Test<T> operator + (const Test<T>& lhs, const Test<T>& rhs)
//{
// return Test<int>(lhs.m_value + rhs.m_value);
//}
T m_value;
};

template<typename T>
Test<T> operator + (const Test<T>& lhs, const Test<T>& rhs)
{
return Test<T>(lhs.m_value + rhs.m_value);
}

main(int argc, char* argv[])
{
Test<int> t1(5);
Test<int> t2(6);
Test<int> t3 = t1 + t2;
}...................................................................................................


Note that since `main` lack a return value specification this code is
invalid as standard C++, and Visual C++ does not compile it.

g++ /should/ diagnose this by default, but MinGW g++ 8.2.0 doesn't even
warn when I explicitly enable the warning,

http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wreturn-type


> I tried gcc and ms vc++. They both have very similar errors.

You should specify the build command(s) /in the question/.

$ g++ prog.cc -Wall -Wextra
-I/opt/wandbox/boost-1.69.0/gcc-8.2.0/include -std=gnu++2a

Instead of a gcc-specific cryptic specification of standard like
"gnu++2a", which could mean anything, use e.g. "c++14".



> What is strange that if we move friend expression before declaring
> any class members then code compiles fine. Or we can remove member
> operator then it compiles too.

Well,

friend Test<T> operator + <T>

is a syntax error.

When you fix that by removing the last `<T>`, g++ helpfully reports that it

"declares a non-template function"

When you fix /that/, by templating the `friend` declaration,

template< class U >
friend Test<U> operator + (const Test<U>& lhs, const Test<U>& rhs);


it compiles.

You then have /two/ operator+ definitions. However, the one inline in
the class has right hand side argument of type `T`, so it's not
considered for the call in `main`. So you get a call of the free function.

When you fix that it still compiles, because the lookup rules are such
that when a definition (or more generally a declaration) is found in the
class, declarations at namespace level are not considered. I.e. you then
get a call of the member version. And I suggest that you just remove
that, because the free function supports implicit conversion in both
argument positions, so it's the more general variant.


Cheers & hth.,

- Alf

red floyd

unread,
Feb 11, 2019, 12:52:03 PM2/11/19
to
On 2/11/2019 1:27 AM, Alf P. Steinbach wrote:

> Note that since `main` lack a return value specification this code is
> invalid as standard C++, and Visual C++ does not compile it.
>
> g++ /should/ diagnose this by default, but MinGW g++ 8.2.0 doesn't even
> warn when I explicitly enable the warning,
>
> http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wreturn-type

As I recall, main() has an implicit "return 0". Unfortunately, the
only standard I have access to at the moment is C++03. In that
standard, see 3.6.1/5:

"... If control reaches the end of main without encountering a return
statement, the effect is that of executing return 0;"

So it is defined, it is valid, and no warning is required. At least
as of C++03.



Alf P. Steinbach

unread,
Feb 11, 2019, 2:14:31 PM2/11/19
to
The problem isn't lack of a `return` statement, it's the implicit `int`.

Cheers!,

- Alf


James Kuyper

unread,
Feb 11, 2019, 2:33:28 PM2/11/19
to
On 2/11/19 12:51, red floyd wrote:
> On 2/11/2019 1:27 AM, Alf P. Steinbach wrote:
>
>> Note that since `main` lack a return value specification this code is
>> invalid as standard C++, and Visual C++ does not compile it.
>>
>> g++ /should/ diagnose this by default, but MinGW g++ 8.2.0 doesn't even
>> warn when I explicitly enable the warning,
>>
>> http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wreturn-type
>
> As I recall, main() has an implicit "return 0". Unfortunately, the
> only standard I have access to at the moment is C++03. In that
> standard, see 3.6.1/5:
>
> "... If control reaches the end of main without encountering a return
> statement, the effect is that of executing return 0;"

Yes, but "the effect of executing return 0;" depends upon how the
function is declared. If it's declared as returning a type that "int"
can be implicitly converted to, the behavior is to convert 0 to that
type and return it. If it's declared as returning any other type, or as
returning void, it's a violation of a diagnosable rule specified by the
standard (9.6.3p2); a diagnostic is required (4.1p2).
And if the function isn't properly declared at all, that lack of
declaration makes it a syntax error (11.3.5p1 - T is not optional, and
is missing from this declaration) regardless of whether there's any
return statement.

In the particular case of main(), there's additional requirements.
6.6.1p2 specifies two different ways to declare main() that all
implementations are required to accept; implementations of C++ have no
obligation to accept any declarations for main() that don't match one of
those two forms. This declaration doesn't match either of them.

red floyd

unread,
Feb 11, 2019, 7:13:01 PM2/11/19
to
Ah, I totally missed the implicit int. I guess it's a case of seeing
what you are expecting to see. Sorry about that, and thanks for
pointing it out!



ailynka...@gmail.com

unread,
Feb 11, 2019, 11:50:36 PM2/11/19
to
Ok.
int main(int argc, char* argv[])
{
Test<int> t1(5);
Test<int> t2(6);
Test<int> t3 = t1 + t2;
}

Obviously question is not about returned value/signature of main.

I don't think "friend Test<T> operator + <T> (const Test<T>& lhs, const Test<T>& rhs);" is syntactic error.

https://en.cppreference.com/w/cpp/language/friend
Go to section friend operators and you will find "friend std::ostream& operator<< <> (std::ostream&, const Foo&);"
If you want you can replace "<T>" by "<>" - effect will be same.

Alf P. Steinbach

unread,
Feb 12, 2019, 1:24:07 AM2/12/19
to
When you post in clc++, expect everything to be dissected. ;-)

It can be a good learning experience.



> I don't think "friend Test<T> operator + <T> (const Test<T>& lhs, const Test<T>& rhs);" is syntactic error.
>
> https://en.cppreference.com/w/cpp/language/friend
> Go to section friend operators and you will find "friend std::ostream& operator<< <> (std::ostream&, const Foo&);"
> If you want you can replace "<T>" by "<>" - effect will be same.

Ooops. You're right.

I've never seen this before, but it picks up the non-static member
function of same name, and somehow thinks this `friend` declaration is a
data member declaration.

One fix is to qualify with namespace:

friend auto ::operator + <T> (const Test<T>& lhs, const Test<T>&
rhs) -> Test<T>;

Which illustrates that something can be repaired without quite
understanding the problem.

That's often the case.

Hopefully others will chime in with an /explanation/.


Cheers!

- Alf

ailynka...@gmail.com

unread,
Feb 13, 2019, 12:38:09 AM2/13/19
to
Yes, workarounds can be used.
But I'd like to know why this error happens. What's wrong with it?
To me all looks fine. Why do compilers stop at first declaration and don't look at other places. Operator's signatures are different.
0 new messages