Program compiles using clang++, but g++ exhausts the RAM and fails - c++

I considered the C++11-based enum bitset introduced here. I came up with some sample program:
#include <bitset>
#include <type_traits>
#include <limits>
template <typename TENUM>
class FlagSet {
private:
using TUNDER = typename std::underlying_type<TENUM>::type;
std::bitset<std::numeric_limits<TUNDER>::max()> m_flags;
public:
FlagSet() = default;
FlagSet(const FlagSet& other) = default;
};
enum class Test
{
FIRST,
SECOND
};
int main(int argc, char *argv[])
{
FlagSet<Test> testFlags;
return 0;
}
The program compiles just fine using clang++ (clang version 3.8.1 (tags/RELEASE_381/final)) via clang++ -std=c++11 -o main main.cc.
However, if I use g++ (g++ (GCC) 6.2.1 20160830) via g++ -std=c++11 -o main main.cc instead, the compiler eventually exhausts system memory. Is this an issue with g++ or is this code somehow not compliant with the standard?

std::bitset<std::numeric_limits<TUNDER>::max()> is 256 MiB in size (assuming 32-bit int). It's great that clang successfully compiles it, but it's not particularly surprising that gcc runs out of memory.
If you're intending to use the enumerators as bitset indices you'll have to pass the largest enumerator in as a separate template parameter; there is as yet (Max and min values in a C++ enum) no way to find the range of an enumeration.
Example:
template <typename TENUM, TENUM MAX>
class FlagSet {
private:
std::bitset<MAX + 1> m_flags;
public:
FlagSet() = default;
FlagSet(const FlagSet& other) = default;
};
enum class Test
{
FIRST,
SECOND,
MAX = SECOND
};
FlagSet<Test, Test::MAX> testFlags;

Related

Statically initializing constexpr std::array of objects containing function pointers

I am trying to statically initialize a constexpr std::array of objects containing function pointers with the following code:
#include <array>
using TVoidVoid = void(*)(void);
class State{
public:
constexpr State(TVoidVoid function) : function_{function}{}
private:
TVoidVoid function_;
};
void OnEvent1(){}
void OnEvent2(){}
constexpr std::array<State, 10> states = {{OnEvent1}, {OnEvent2}};
int main(){}
I am compiling with:
g++ -Wall -Wextra -Wshadow -Weffc++ -Wstrict-aliasing -ansi -pedantic -Werror -std=c++14 main.cpp
I have trouble understanding the compiling error I'm getting:
main.cpp:14:69: error: too many initializers for ‘const std::array<State, 10>’
constexpr std::array<State, 10> states = {{OnEvent1}, {OnEvent2}}
The compiler is g++ (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0.
What could be the problem here? Many thanks in advance!
The error message could be better. But what's tripping the initialization is in fact that you don't have enough braces. Recall that a std::array is an aggregate wrapping a raw array. So you need to initialize like this:
constexpr std::array<State, 10> states = {{ {OnEvent1}, {OnEvent2} }};
Otherwise, the somewhat inaccurate brace ellision detection algorithm assumes {OnEvent1} is to initialize the internal array, and the second clause is redundant.
Now you just need to provide a default c'tor for State, or adjust the array size.
You need a default constructor (for the last 8)
#include <array>
using TVoidVoid = void(*)(void);
class State{
public:
// This static is equivalent to a TVoidVoid
// used by the default constructor
static void DefFunct() {}
constexpr State(TVoidVoid function) : function_{function}{}
// We create a default constructor for the
// empty elemnts of the array with our function
constexpr State() : function_(DefFunct) {}
private:
TVoidVoid function_;
};
void OnEvent1(){}
void OnEvent2(){}
constexpr std::array<State, 10> states = {OnEvent1, OnEvent2};
int main(){}

Constructor with mis-typed default value raises no error with GCC 7

In the following code, the variable definition B<int, int>(14); should be erroneous:
#include <iostream>
struct A {
};
template<class T, class R=A>
class B {
public:
explicit B(const int s, R n = A()) {
std::cout << "c\n";
}
};
template <class T, class R=A>
void foo(const int s, R nx = A()) {};
int main() {
B<int, int>(14);
// foo<int, int>(14);
// error: could not convert ‘A()’ from ‘A’ to ‘int’
}
Why does it cause no compilation error?
I compiled the code with gcc 7.3 and g++ -std=c++17
When I compile the code with gcc 7.3 and g++ -std=c++14, I get an error.
I thought that line uses the default value for parameter n in constructor of B.
The default value of n is A(), which is not convertible to an int.
And I should get a compilation error. But that is not the case.
The similar case for function (as tested by foo) would cause compilation error.
You have run into GCC bug #83020. Clang 6 and GCC 8 (as well as GCC 6) correctly reject your example code, as does GCC 7 in C++14 mode.

Symbol not found in debugger only, when having templated template argument

Given the following code as test.cpp,
Building using clang++ -c test.cpp -o test.o -g; clang++ test.o -g -all_load, setting breakpoint at return a.getValue(); and attempting to p a.getValue() from lldb:
Running llvm 3.8.0 on unix - works perfectly
Running xcode or llvm 8.1.0 on OSX - I get the following error:
error: Couldn't lookup symbols:
__ZNK4Test7MyClassILi2ELi3EE8getValueEv
Two interesting facts:
If I remove the last template argument - all works well
If I build directly without going through the .o file (clang++ test.cpp) = all goes well
Anyone has a clue what is going on, and how can it be fixed?
namespace Test{
template<class T>
class BLA{
public:
T getBlaValue() const{return 3;}
};
template <int N1, int N2, template<class T>class Impl = BLA>
class MyClass {
private:
public:
__attribute__((used))
int getValue() const
{
return 3;
}
};
}
int main()
{
Test::MyClass<2, 3> a;
return a.getValue();
}

Common syntax for declaring and initializing constexpr on MSVC and GCC

namespace MyNS {
template <>
class Test<Test1> {
public:
constexpr static char const *description[] = { "X`", "Y1"};
/*
...
...
*/
}
constexpr char const * Test<Test1>::description[];
/* Above definition is required when compiling with GCC but MSVC compiler gives error saying 'description' is redeclared. */
/* **Omitting definition of 'description', which is written outside class in namespace, causes successful compilation by MSVC but failure in GCC** */
}
Is there a common way to define, declare and initialize above constexpr such that code compiles successfully by both MSVC and GCC?
This code:
#include <iostream>
namespace MyNS {
template<class T> struct Test;
template <>
struct Test<int> {
constexpr static char const * description[] = { "X1", "Y1"};
};
}
int main() {
std::cout << MyNS::Test<int>::description[0];
return 0;
}
Compiles -as far as I can tell- using
g++-4.8+ -std=c++11
g++-4.8+ -std=c++1y
g++-4.9+ -std=c++14
g++-6.1+
g++-6.1+ -std=c++11
g++-6.1+ -std=c++14
without and further definition (where 4.8+ means starting from g++ version 4.8 and onwards).

template lambda sometimes doesn't compile

I would like to implement a generic visitor pattern for my trie data structure. Below is the extracted minimal fragment which makes trouble for compilers:
#include <functional>
struct Node {
size_t length;
};
template<typename N>
class C {
public:
size_t longest = 0;
std::function<void(const N )> f = [this](N node) {
if(node->length > this->longest) this->longest = node->length;
};
};
int main() {
Node n;
n.length = 5;
C<Node*> c;
c.f(&n);
}
It compiles with g++ (Ubuntu/Linaro 4.7.2-2ubuntu1), Ubuntu clang version 3.4-1ubuntu3 and with Apple LLVM version 5.0 (clang-500.2.79). icc (ICC) 14.0.2 says:
try_lambda_T.cc(15): error: "this" cannot be used inside the body of this lambda
if(node->length > this->longest) this->longest = node->length;
I found a similar post:
Class with non-static lambda member can't use default template paramers?
That story resulted in a bug report which was resolved in g++ 4.8.1:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54764
However, g++ (Ubuntu 4.8.2-19ubuntu1) results in:
internal compiler error: in tsubst_copy, at cp/pt.c:12125
std::function<void(const N )> f = [this](N node) {
^
Please submit a full bug report,
with preprocessed source if appropriate.
What can I do with it to have it compiled newest g++ (and, hopefully, icc)?
gcc-4.8.1 compiles the code if you don't use a non-static data member initializer to initialize f
template<typename N>
class C {
public:
C()
: f([this](N node) {
if(node->length > longest) longest = node->length;
})
{}
size_t longest = 0;
std::function<void(const N )> f;
};
Live demo
It even works if you prefer referring to longest as this->longest within the body of the lambda.