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.)
Related
This question already has answers here:
constexpr static member before/after C++17
(1 answer)
Defining static const integer members in class definition
(7 answers)
Closed 4 years ago.
The following only links successfully with -std=c++17 or above. -std=c++14 or below gives an unresolved external error:
In function `C::f()':
C.cpp:(.text+0x19): undefined reference to `C::kConstant'
Why doesn't this work with the c++14 standard and does work with the c++17 standard? (tested with both GCC and Clang)
And why does the commented-out workaround work even on c++14?
C.h
#pragma once
class C {
public:
static constexpr int kConstant = 10;
int f();
};
C.cpp
#include "C.h"
#include <algorithm>
int C::f()
{
// This only works with -std=c++17 or above
return std::min (1, kConstant);
// This works even with -std=c++14
// return std::min (1, static_cast<int> (kConstant));
}
Main.cpp
#include "C.h"
int main()
{
C c;
c.f();
}
Wandbox
Update: This question isn't an exact duplicate, but has an answer which answers most of my question. It doesn't answer why the workaround works with -std=c++14, though, and the original doesn't. Is it perhaps because in the original the variable is odr-used, and in the workaround it is not?
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.
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.
This question already has answers here:
How to detect existence of a class using SFINAE?
(4 answers)
Closed 6 years ago.
I'd need a template which can be called like this:
int x = type_exists< std::vector<int> >::value;
This should set x to 1 if #include <vector> was present (either explicitly or transitively) earlier in the source, otherwise it should set x to 0.
Is it possible to do it in C++? I'm using GCC, so GCC extensions are also fine.
It's also OK to change the call syntax a bit.
It's not OK to run the C++ compiler twice: first just to figure out if we get a compile error.
This is not what you are looking for, but it's as close as you can get to a type_exists trait:
template<class T> struct Void { typedef void type; };
template<class T, class U = void>
struct type_exists { enum { value = 0 }; };
template<class T>
struct type_exists<T, typename Void<T>::type> { enum { value = 1 }; };
Apparently, it works:
static_assert(type_exists<int>::value, "int is not defined");
static_assert(type_exists<SomeNonexistingType>::value, "expected compile-time error");
This does exactly what it is supposed to do. Tested with GCC 5.4.0.
This is not possible, I'm afraid. If we were to use a non defined identifier we would get a compilation error, leading to this code:
int x = type_exists< std::vector<int> >::value;
not to even compile.
Also, the standard doesn't specify any preprocessor directive to be declared within the header file (which is implementation defined instead) for the standard library, therefore you won't be able to detect it even with preprocessor macros.