Why does this private template function compile? -> Compiler Bug VS 2009 - c++

This compiles with out problems in VS 2009? Am I stupid?
GCC gives a warning, that the template is private....?
What am I missing?
#include <iostream>
using namespace std;
class A
{
private:
template<typename T>
A& operator<<(const T & v)
{
cout << v << endl;
return *this;
}
};
int main()
{
A a;
a << 4;
system("pause");
}

Microsoft acknowledges the bug and claims it will be fixed in the next major release for the compiler (which I read as VC11/VS-whatever-is-after-2010 - probably not a service pack for VC10/VS2010):
http://connect.microsoft.com/VisualStudio/feedback/details/649496/visual-c-doesnt-respect-the-access-modifier-for-operator-member-function-templates
from the comments, the fix appears to be already made to an internal compiler build.

This code should not compile - this is a bug (or silly extension) in VS. GCC should refuse it as well. The operator is inaccessible in the scope it is used.
Comeau treats this correctly:
"ComeauTest.c", line 28: error: function "A::operator<<(const T &) [with T=int]"
(declared at line 14) is inaccessible
a << 4;
EDIT: A relevant standard snippet, from 13.3/1
[Note: the function selected by
overload resolution is not guaranteed
to be appropriate for the context.
Other restrictions, such as the
accessibility of the function, can
make its use in the calling context
ill-formed. ]

No, you're not stupid - it's broken code and should be rejected. The Comeau compiler (http://www.comeaucomputing.com/tryitout) does correctly reject it.

Related

Expected ambiguity error on clang is not present

This needs little explanation, but I'm expecting to get an ambiguity error from the following C++ code, however my compiler gives me different results that are apparently not part of the standard.
Environment:
Windows
Clang++ version 12.0.0
Clang++ target = x86_64-pc-windows-msvc
#include <iostream>
void print(int x) {
std::cout << "INT\n";
}
void print(double d) {
std::cout << "DOUBLE\n";
}
int main() {
print(5l); // 5l is type long, should cause ambiguity
}
output:
INT
Any idea why this is happening? My compiler is choosing the function taking an int for some reason instead of issuing an ambiguity error since it shouldn't be able to resolve the function call. Is there some conversion logic that I missed? Do I need to turn up some 'error levels' or something along those lines? Or is this a bug in the compiler? Thanks.
Turned out I had to add -fno-ms-compatibility to my clang compiler flags to switch off MSVC compatibility.

cast operator function compiles fine in g++ but not in other compilers. Why? [duplicate]

This question already has an answer here:
Operator cast, GCC and clang: which compiler is right?
(1 answer)
Closed 6 years ago.
Consider following program:
struct S {
using T = float;
operator T() { return 9.9f; }
};
int main() {
S m;
S::T t = m;
t = m.operator T(); // Is this correct ?
}
The program compiles fine in g++ ( See live demo here )
But it fails in compilation in clang++, MSVC++ & Intel C++ compiler
clang++ gives following errors ( See live demo here )
main.cpp:8:20: error: unknown type name 'T'; did you mean 'S::T'?
t = m.operator T(); // Is this correct ?
^
S::T
main.cpp:2:11: note: 'S::T' declared here
using T = float;
MSVC++ gives following errors ( See live demo here )
source_file.cpp(8): error C2833: 'operator T' is not a recognized operator or type
source_file.cpp(8): error C2059: syntax error: 'newline'
Intel C++ Compiler also rejects this code ( See live demo here )
So, the question is which compiler is right here ? Is g++ incorrect here or other 3 compilers are incorrect here ? What C++ standard says about this ?
[basic.lookup.classref]/7:
If the id-expression is a conversion-function-id, its conversion-type-id is first looked up in the class of the object expression and the name, if found, is used. Otherwise it is looked up in the context of the entire
postfix-expression. In each of these lookups, only names that denote types or templates whose specializations are types are considered. [ Example:
struct A { };
namespace N {
struct A {
void g() { }
template <class T> operator T();
};
}
int main() {
N::A a;
a.operator A(); // calls N::A::operator N::A
}
— end example]
This indicates that the example could be fine, although in the above example, A has previously been declared as a type name, visible to main.
This was discussed in core issue 156, filed all the way back in 1999:
How about:
struct A { typedef int T; operator T(); };
struct B : A { operator T(); } b;
void foo() {
b.A::operator T(); // 2) error T is not found in the context
// of the postfix-expression?
}
Is this interpretation correct? Or was the intent for this to be an
error only if T was found in both scopes and referred to different
entities?
Erwin Unruh: The intent was that you look in both contexts. If you find it only once, that's the symbol. If you find it in both, both symbols must be "the same" in some respect. (If you don't find it, its an error).
So I'd say that Clang is wrong: the intent, as expressed in the wording to some extent, is that we find T, even if only in the class.

ADL related GCC 4.7.2 issue with expression SFINAE

Take the following code, which is characterized by
Reliance on ADL for a specific behavior (volume)
Using decltype for return type and relying on SFINAE to discard extra overloads
namespace Nature {
struct Plant {};
double volume(Plant){ return 3.14; }
}
namespace Industrial {
struct Plant {};
double volume(Plant) { return 100; }
}
namespace SoundEffects {
// A workaround for GCC, but why?
////template<class T> void volume();
template<class aSound>
auto mix(aSound& s) -> decltype(volume(s)*0.1)
{
return volume(s)*.1;
}
struct Samples {
Nature::Plant np;
Industrial::Plant ip;
};
inline double mix(const Samples& s) {
return mix(s.np) + mix(s.ip);
}
}
int main()
{
SoundEffects::Samples s;
assert( mix(s) == 100*.1 + 3.14*.1 );
}
The code as presented (without the template<class T> void volume() line), VS 2012 and clang 3.5 compiles successfully, and runtime is as expected. However, GCC 4.7.2 says:
template-function-overload.cpp: In substitution of 'template<class aSound> decltype ((volume(s) * 1.0000000000000001e-1)) SoundEffects::mix(aSound&) [with aSound = SoundEffects::Samples]':
template-function-overload.cpp:46:4: required from here
template-function-overload.cpp:23:9: error: 'volume' was not declared in this scope
template-function-overload.cpp:23:9: note: suggested alternatives:
template-function-overload.cpp:9:11: note: 'Nature::volume'
template-function-overload.cpp:14:11: note: 'Industrial::volume'
With the extra template volume line, all three compile and run fine.
So, there is clearly a compiler defect here. My question is, which compiler is the defective one? And which C++ standard is being violated?
This was a bug which was fixed since GCC 4.8. Here's a simplified version of the code that gives the same error:
template<class T>
auto buzz(T x) -> decltype(foo(x));
void buzz(int);
int main() {
buzz(5); // error: 'foo' was not declared in this scope
}
In mix(s), both overloads of SoundEffects::mix are compiled into the set of candidate overloads via ADL (SoundEffects is an associated namespace of SoundEffects::Sample). The function template overload is evaluated for viability. The error occurs because volume(s) cannot be resolved to a suitable overload either via pure unqualified lookup or ADL for Sample.
The reason this should pass is that when lookup fails a substitution failure should occur (since volume(s) is dependent) and the template should be rejected from overload resolution. This would leave mix(const Sample&) as the only viable overload to select. The fact that there is a hard error is clearly a sign that this GCC version has a faulty SFINAE implementation.

Using clang 3.1 with initializer lists

When I compile this code:
template<typename T>
struct S {
std::vector<T> v;
S(initializer_list<T> l) : v(l) {
std::cout << "constructed with a " << l.size() << "-element list\n";
}
};
using the following command line:
clang++ -std=c++11 -stdlib=libc++ initializer_list.cpp
I get the following error.
initializer_list.cpp:12:23: error: expected ')'
S(initializer_list<T> l) : v(l) {
Does anyone know the fix if any??
Thanks in advance
You probably meant to write std::initializer_list<T>. Make sure you include <initializer_list>.
Your code sample is incomplete. It would be useful if you can provide a complete example. The problem with the code as written is that you're missing
#include <initializer_list>
#include <vector>
#include <iostream>
... and initializer_list is in namespace std, so you're also missing a std:: from your constructor declaration.
However, since you've claimed that neither of these is the issue, the most likely cause would seem to be that your C++ standard library implementation doesn't provide std::initializer_list. That would be the case if Clang is using GCC's libstdc++, and you do not have a suitably new version of that installed: you need at least version 4.4, but note that a patch is required to fix bugs in libstdc++-4.4 in order to make it work with Clang in C++11 mode, otherwise you will get errors about type_info and various other problems.
Also, you say that the diagnostic you received is this:
initializer_list.cpp:12:23: error: expected ')'
S(initializer_list<T> l) : v(l) {
^
(I've reconstructed the caret from the provided column number; it would be useful to preserve it in future questions.) For any of the above explanations, this will not be the first diagnostic which Clang produces; that would be something along the lines of:
initializer_list.cpp:12:5: error: no template named 'initializer_list'; did you mean 'std::initializer_list'?
S(initializer_list<T> l) : v(l) {
^~~~~~~~~~~~~~~~
std::initializer_list
So either you've missed out the first diagnostic from your question, or the problem is that you have declared some other (non-template) type named initializer_list in the code you omitted in your question, and that is hiding std::initializer_list. Without seeing the rest of your code or the rest of your diagnostics, it's not possible to tell which.

Invalid conversion to non-const reference in C++0x... bug in std::pair?

I have been developing a library that is getting pretty large, and now I am adding some template-based parts that use C++0x features. So I tried to compile my library (which compiled entirely without warnings on the current standard) with the flag -std=c++0x using gcc version 4.4.5 (on Linux). Now I got a huge influx of error messages related to the conversion of "temporaries" variables to non-const references. The problem is, they are not temporary!
Here is a small piece of code that reproduces the error:
#include <iostream>
#include <map>
struct scanner {
scanner& operator &(std::pair<std::string, int&> i) {
std::cout << "Enter value for " << i.first << ": ";
std::cin >> i.second;
return *this;
};
};
struct vect {
int q[3];
void fill(scanner& aScan) {
aScan & std::pair<std::string, int&>("q0",q[0])
& std::pair<std::string, int&>("q1",q[1])
& std::pair<std::string, int&>("q2",q[2]);
};
};
int main() {
vect v;
scanner s;
v.fill(s);
return 0;
};
If you compile this with the current standard (no c++0x flag) it will compile and run as expected. However, if you compile it with -std=c++0x, it will throw the following error at compile-time:
/usr/include/c++/4.4/bits/stl_pair.h:94: error: invalid initialization of non-const reference of type ‘int&’ from a temporary of type ‘int’
I really can't figure this out. I have looked over the web and SO, but none seem to have this problem. Is it a bug in std::pair? I would really like to know what the problem is.. thank you for any insight you can give.
PS: don't complain about the "quality" or "stupidity" of the code above, it is not real code.. just an example that shows the error.
Your code is not valid C++03, comeau gives (after adding a return statement to op&):
"stl_pair.h", line 44: error: qualifiers dropped in binding reference of
type "int &" to initializer of type "const int"
pair(const _T1& __a, const _T2& __b) : first(__a), second(__b) {}
^
detected during instantiation of "std::pair<_T1, _T2>::pair(const
_T1 &, const _T2 &) [with _T1=std::string, _T2=int &]" at
line 17 of "ComeauTest.c"
...
The problem is a reference inside a pair. If I remember correctly, it is a gcc extension that allows this. Gcc does accept it with -std=gnu++98, which is the default for C++, but with -std=c++98, gcc 4.4.3 gives:
In file included from /usr/include/c++/4.4/bits/stl_algobase.h:66,
from /usr/include/c++/4.4/algorithm:61,
from PREAMBLE:7:
/usr/include/c++/4.4/bits/stl_pair.h: In instantiation of ‘std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, int&>’:
<input>:5: instantiated from here
/usr/include/c++/4.4/bits/stl_pair.h:83: error: forming reference to reference type ‘int&’
...
There are LOTS of bugs in gcc C++0x support, it's very much unfinished and development is ongoing. This is doubly true for a version as old as gcc-4.4.5. If you're serious about starting C++0x development before the standard is ratified, you need to use the bleeding-edge version of the compiler and standard library.
It compiles fine both with and without -std=c++0x with GCC 4.5.2.
I guess GCC 4.4.5 doesn't support C++0x that much to get this working.
Except for the missing return *this; in scanner& operator &(std::pair<std::string, int&> i), your code is valid C++0x.