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.
Related
This code does not compile using gcc HEAD 10.0.0 20190 but compiles using clang HEAD 9.0.0
#include <iostream>
struct A
{
A() = default;
A( int ) {}
};
struct B
{
B() = default;
B( const char * ) {}
};
template <typename...Bases>
struct C : Bases...
{
using Bases::Bases...;
};
int main()
{
}
The error is
rog.cc:18:23: error: parameter packs not expanded with '...':
18 | using Bases::Bases...;
| ^~~
prog.cc:18:23: note: 'Bases'
Expansions are only allowed in using-declarations since C++17. (ref)
Looks like your GCC version just doesn't have that new feature yet, or does but in a buggy way (e.g. bug 79094).
I'm trying to implement a simple system using template struct, the code is very simple and compile fine with MSVC, yet i cannot understand why CLANG gives me this error: "lld-link : error : undefined symbol: public: static struct FMyStruct const TSpec<1>::m_struct"
I compile on a windows 64bitmachine with VisualStudio IDE but CLANG LLVM as compiler. The code works fine with MSVC.
I simplified my problem to the very minimum, i tried to put everything in one single cpp file, with no result. I also tried explicit template instanciation.
I want to be compliant with C++14, no C++17. One thing i tried that worked was declaring the m_struct member as an inline variable, but then i get this warning: "inline variables are a C++17 extension"
struct FMyStruct
{
const int _p0;
const int _p1;
const int _p2;
};
template< int > struct TSpec {
static constexpr FMyStruct m_struct = { 0, 0, 0 };
};
FMyStruct
Function( int i )
{
return TSpec< 1 >::m_struct;
}
int main()
{
return 0;
}
Result:
"lld-link : error : undefined symbol: public: static struct FMyStruct const TSpec<1>::m_struct"
I expect the linker to find the symbol m_struct since it is defined very next to it ...
The weirdest part is that if i try:
int
Function( int i )
{
return TSpec< 1 >::m_struct._p0;
}
the program will compile fine.
Edit: My CLANG version is 9.0.0, prebuilt distributed version for windows from the official website.
clang version 9.0.0 (trunk)
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: C:\Program Files\LLVM\bin
It indeed seems to be a bug related to the CLANG version, thanks #Sombrero Chicken for pointing this out.
So this is definitely weird but i managed to solve this avoiding the C++17-specific 'inline' declaration of the static member by adding this after the template struct definition:
template< int N > const FMyStruct TSpec< N >::m_struct;
By the way, it does not seem to be related to the template declaration at all.
For summary, it gives this program that will compile fine.
struct FMyStruct
{
const int _p0;
const int _p1;
const int _p2;
};
template< int > struct TSpec {
static constexpr FMyStruct m_struct = { 0, 0, 0 };
};
template< int N > const FMyStruct TSpec< N >::m_struct;
FMyStruct
Function( int i )
{
return TSpec< 1 >::m_struct;
}
int main()
{
return 0;
}
I still do not really understand why this is necessary since the static member is public to the struct, and part of the same unit & file; i guess this is a different matter but i'd like to be enlightened. Thank you.
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.
I have a map like so map<string, unique_ptr<Base>> variables and I am trying to insert data into the map variables.insert(make_pair("foo", new Int(10))) but I am getting to following errors:
error: no matching function for call to ‘std::map<std::__cxx11::basic_string<char>, std::unique_ptr<Base>>::insert(std::pair<const char*, Int*>)’
variables.insert(make_pair("test", new Int(10)));
error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
template<typename _Pair, typename = typename
This is my code:
class Base {
public:
Base() {};
virtual ~Base() {};
};
class Int : public Base {
public:
Int(int i) {
this->i = i;
}
Int operator=(int i) {
this->i = i;
}
int i;
};
void set() {
map<string, unique_ptr<Base>> variables;
variables.insert(make_pair("test", new Int(10)));
}
I think I need a fresh pair of eyes to look at this I'm not sure what this issue is, thanks!
Edit
I'm trying to make a heterogeneous map and there's a class for each data type. But I still get the same error no matter how many there are.
Note: This answer only applies to older versions of the main three compilers:
GCC: Applies to 5.3.1 or earlier. May apply to any version earlier than 6.1.0, but I haven't tested this.
Clang: Applies to 3.7.1 or earlier. May apply to any version earlier than 3.8.0, but I haven't tested this.
Visual Studio: Applies to 19.00.23506.0 or earlier. May apply to any version earlier than 19.00.23720.0, but I haven't tested this.
Conversely, if you have GCC 6.1.0 or later, Clang 3.8.0 or later, or Visual Studio 19.00.23720.0 or later, the original code should compile as is, without either of the modifications suggested in this answer.
[Thanks goes to AndyG for pointing out that it works with later versions of GCC & Clang.]
The problem appears to be that it isn't creating your unique_ptr from your raw pointer.
If you can use C++14, try std::make_unique().
void set() {
map<string, unique_ptr<Base>> variables;
variables.insert(make_pair("test", make_unique<Int>(10)));
}
If you can't, then try something like this:
void set() {
map<string, unique_ptr<Base>> variables;
variables.insert(make_pair("test", unique_ptr<Int>(new Int(10))));
}
Interestingly, I noticed a slight difference in how different compilers handle this. Using the following slightly modified version of your code as a test program:
#include <map>
#include <memory>
#include <iostream>
class Base {
public:
Base() {};
virtual ~Base() {};
};
class Int : public Base {
public:
Int(int i) {
this->i = i;
}
Int& operator=(int i) {
this->i = i;
// You forgot to return something.
return *this;
}
int i;
};
void set() {
using namespace std;
map<string, unique_ptr<Base>> variables;
variables.insert(make_pair("test", new Int(10)));
// C++14:
// variables.insert(make_pair("test", make_unique<Int>(10)));
// C++11:
// variables.insert(make_pair("test", unique_ptr<Int>(new Int(10))));
// Cheap hack for testing.
cout << static_cast<Int*>(variables["test"].get())->i << endl;
}
int main() {
set();
}
Most compilers* will fail to compile this, unless the initial line is commented out and either of the fixes is uncommented. However, the online MSVC compiler seemed to be able to compile it fine, without needing to uncomment either of the lines. Curiously, the version of MSVC available on Rextester failed to compile it without uncommenting one of the two lines.
* Tested online, with TutorialsPoint GCC, MSVC 2015 online, and Rextester Clang, GCC, and MSVC.
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;