This question already has an answer here:
get<string> for variants fail under clang++ but not g++
(1 answer)
Closed 4 years ago.
The following uses of std::visit compiles properly under gcc 7.2 but fails to compile under clang 5.0. Does anyone know what the problem is?
#include <variant>
struct S1 {int foo() { return 0; }};
struct S2 {int foo() { return 1; }};
using V = std::variant<S1, S2>;
int bar() {
V v;
return std::visit([](auto& s) { return s.foo(); }, v);
}
The first error is this:
include/c++/7.2.0/variant:238:46: error: cannot cast 'std::variant<S1, S2>' to its private base class
'std::__detail::__variant::_Variant_storage<true, S1, S2>'
return __get(std::in_place_index<_Np>, std::forward<_Variant>(__v)._M_u);
Here is a link to godbolt shows this error: https://godbolt.org/g/5iaKUm
This is known bug 33222 that seems to only affect libstdc++'s std::variant (and other constructs using the same combination). The problem is related to friend function to templates - see the thread for more detail.
The variant from libc++ doesn't seem to use the technique of friends that libstdc++ used, so you might want to temporarily change to libc++ in the meantime.
Small update: This has been fixed in the latest trunk.
Related
This question already has answers here:
Can a method be referenced using a child class name in C++?
(2 answers)
Closed 6 months ago.
godbot
While doing some C++ templates coding, I came accross something that compiles for Clang but failed for GCC, it's like something below:
#include <iostream>
struct B {
virtual void foo() {
std::cout << "B::foo" << std::endl;
}
};
struct D:B {
};
int main(int argc, char* argv[]) {
D* d = new D();
static_cast<B*>(d)->D::foo();
delete d;
}
I want to know if the behavior of the code above well-defined according to C++ standard?
GCC is correct in this case, the program is ill formed. You cannot call a method of D from an instance of B directly without casting (in other words, undoing your initial upcast).
https://godbolt.org/z/b43zcWMqe
Both Clang and GCC should emit something to the effect of
<source>:14:26: error: 'D' is not a base of 'B'
14 | static_cast<B*>(d)->D::foo();
This question already has an answer here:
Template class compiles with C++17 but not with C++20 if unused function can't be compiled
(1 answer)
Closed 8 months ago.
We came an interesting case where MSVC doesn't check namespace resolution for unused functions in a templated class. For example:
#include <string>
namespace
{
template<class Iterator>
struct Foo
{
Foo()
{
}
void parse(Iterator begin, Iterator end)
{
foo::string a(begin, end - begin);
}
};
}
using CharFoo = Foo<const char *>;
CharFoo fooParser;
int main()
{
}
This compiles and runs just fine in MSVC, but gcc and clang both give an error. Is this an MSVC bug technically? Does the C++ standard say anything about this case as to whether or not this is an error?
In general MSVC does NOT compile any template functions if they are not used at all. Most compilers differ in that point -- they always check the code (where I do not know what the C++ standard says.)
This question already has an answer here:
Why C++ containers don't allow incomplete types?
(1 answer)
Closed 6 years ago.
It seems that std::deque does not allow to use it in a recursive way with clang on osx when not using libstdc++ (10.9+ target)
#include <deque>
struct node { std::deque<node> childs; };
int main() {
node n;
}
This simple code compile with clang only if I set MACOS_DEPLOYMENT_TARGET=10.8 (because the clang compiler links with libstdc++) but it gives a lot of errors if I try to compile with libc++ (default c++ target on 10.9+), while with gcc 4/5 it works without problems...
It's a compiler bug or the standard does not allow this? It's seems a quite obvious use of a container...
In general, you should not expect this code to compile. To be sure that it compiles with any standard-compliant compiler you must use an extra level of indirection in one of the following or similar ways:
struct node { std::deque<node> *children; };
struct node { std::unique_ptr<std::deque<node>> children; };
struct node { std::deque<node*> children; };
This question already has answers here:
Injected class name compiler discrepancy
(3 answers)
Closed 6 years ago.
namespace fooo {
class Fooo {
public:
int a;
};
}
namespace fooo {
class Test {
public:
Test(Fooo::Fooo *i) {
i->a = 1;
}
};
}
This code compiles fine with clang (any version) but fails with gcc.
Can anyone explain why?
EDIT:
Yes, I know the issue here is kinda obvious but why does clang accept it? The person who told me this said that this is a bug in the standard and that there is a Defect Report. Can anyone point to the actual DR?
The error message from gcc tells you exactly what the problem is:
t.cpp:11:16: error: ‘fooo::Fooo::Fooo’ names the constructor, not the type
Test(const Fooo::Fooo *i) {
^
it is suprising that clang doesn't give an error.
Following code fails with a error message :
t.cpp: In function `void test()':
t.cpp:35: error: expected primary-expression before '>' token
t.cpp:35: error: expected primary-expression before ')' token
Now I don't see any issues with the code and it compiles with gcc-4.x and MSVC 2005 but not with gcc-3.4 (which is still quite popular on some platforms).
#include <string>
#include <iostream>
struct message {
message(std::string s) : s_(s) {}
template<typename CharType>
std::basic_string<CharType> str()
{
return std::basic_string<CharType>(s_.begin(),s_.end());
}
private:
std::string s_;
};
inline message translate(std::string const &s)
{
return message(s);
}
template<typename TheChar>
void test()
{
std::string s="text";
std::basic_string<TheChar> t1,t2,t3,t4,t5;
t1=translate(s).str<TheChar>(); // ok
char const *tmp=s.c_str();
t2=translate(tmp).str<TheChar>(); // ok
t3=message(s.c_str()).str<TheChar>(); // ok
t4=translate(s.c_str()).str<TheChar>(); // fails
t5=translate(s.c_str()).template str<TheChar>(); // ok
std::cout << t1 <<" " << t2 <<" " << t3 << " " << t4 << std::endl;
}
int main()
{
test<char>();
}
Is it possible to workaround it on the level of translate function and message class, or maybe my code is wrong, if so where?
Edit:
Bugs related to template-functions in GCC 3.4.6 says I need to use keyword template but should I?
Is this a bug? Do I have to write a template keyword? Because in all other cases I do not have to? And it is quite wired I do not have to write it when I use ".c_str()" member function.
Why gcc-4 not always an option
This program does not starts when compiled with gcc-4 under Cygwin
#include <iostream>
#include <locale>
class bar : public std::locale::facet {
public:
bar(size_t refs=0) : std::locale::facet(refs)
{
}
static std::locale::id id;
};
std::locale::id bar::id;
using namespace std;
int main()
{
std::locale l=std::locale(std::locale(),new bar());
std::cout << has_facet<bar>(l) << std::endl;
return 0;
}
And this code does not compiles with gcc-4.3 under OpenSolaris 2009- broken concepts checks...
#include <map>
struct tree {
std::map<int,tree> left,right;
};
As mentioned elsewhere, that seems to be a compiler bug. Fair enough; those exist. Here's what you do about those:
#if defined(__GNUC__) && __GNUC__ < 4
// Use erroneous syntax hack to work around a compiler bug.
t4=translate(s.c_str()).template str<TheChar>();
#else
t4=translate(s.c_str()).str<TheChar>();
#endif
GCC always defines __GNUC__ to the major compiler version number. If you need it, you also get __GNUC_MINOR__ and __GNUC_PATCHLEVEL__ for the y and z of the x.y.z version number.
This is a bug in the old compiler. Newer GCC's, from 4.0 to (the yet unreleased) 4.5, accept it, as they should. It is standard C++. (Intel and Comeau accept it also.)
Regarding cygwin and opensolaris, of course gcc-3.4 is not the only option: the newer versions (the released 4.4.3, or the unreleased 4.5 branch) work fine on these OS'es. For cygwin, it's part of the official distribution (see the gcc4* packages in the list). For opensolaris, you can compile it yourself (and instructions on how to do so can easily be found with Google).
I would try to use a different workaround, since adding the template disambiguator there is incorrect and will break if you move to a different compiler later on.
I don't know the real code, but passing a regular std::string seems to work (option 1: avoid converting to const char * just to create a temporary) or you could provide an overloaded translate that takes a const char* as argument (if the compiler does not complain there), depending on your requirements.