Constructor that takes nulltpr_t: function definition does not declare parameters - c++

I have the following code:
class C {
private:
void *data;
public:
constexpr C(nullptr_t) : data(nullptr) { }
C(int i) : data(new int(i)) { }
};
I have created a constructor which takes nullptr_t, so that I can have code similar to the following:
C foo(2);
// ...
foo = nullptr;
Code similar to this has worked previously on MSVC, however this code fails to compile on GCC 5.3.1 (using -std=c++14) with on the closing bracket of C(nullptr_t) with error: function definition does not declare parameters. Even if i give the parameter a name (in this case _), I get error: expected ')' before '_'. This also fails if the constexpr keyword is removed.
Why am I unable to declare such a constructor, and what are any possible workarounds?

You must be a fan of "using namespace std", and you just got tripped up by it:
constexpr C(std::nullptr_t) : data(nullptr) { }
gcc 5.3.1 compiles this, at --std=c++14 conformance level:
[mrsam#octopus tmp]$ cat t.C
#include <iostream>
class C {
private:
void *data;
public:
constexpr C(std::nullptr_t) : data(nullptr) { }
C(int i) : data(new int(i)) { }
};
[mrsam#octopus tmp]$ g++ -g -c --std=c++14 -o t.o t.C
[mrsam#octopus tmp]$ g++ --version
g++ (GCC) 5.3.1 20160406 (Red Hat 5.3.1-6)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Related

g++ does not link depending on optimization settings

So, this is eating me for the last two days:
I can't link my application, depending on which compiler I use and what optimizations levels are used:
gcc plays nicely with -O1, -O2, -O3 but fails with -O0 and
clang plays nicely with -O2 and -O3 and fails with -O1 and -O0.
There are a bunch of horrible templates in it, but I see no reason for this obscure behaviour.
Here is a minimal amount of code that reproduces the problem:
#include <map>
#include <memory>
#include <iostream>
using id_type = long;
class CB : public std::enable_shared_from_this<CB>
{
public:
CB() = default;
virtual ~CB() = default;
};
template<class F, class C> class SC : public CB
{
};
class FB
{
public:
virtual ~FB() = default;
template<class T, class B> T* as(B* v) const { return dynamic_cast<T*>(v);}
};
template<class T>
class F : public FB
{
public:
virtual std::shared_ptr<CB> create() const
{
auto n = std::make_shared<T>();
return n;
}
};
struct B
{
virtual ~B() = default;
static const id_type ID = 1;
};
class A : virtual public B, virtual public SC<A, B>
{
public:
A() = default;
};
static std::map<id_type, std::shared_ptr<FB>> crtrs {
{A::ID, std::make_shared<F<A>>()}
};
int main()
{
std::cout << crtrs.size();
}
Here is the same online https://gcc.godbolt.org/z/sb9b5E
And here are the error messages:
fld#flap ~/work/p/test1
> $ g++ -O1 main.cpp
fld#flap ~/work/p/test1
> $ g++ -O2 main.cpp
fld#flap ~/work/p/test1
> $ g++ -O3 main.cpp
fld#flap ~/work/p/test1
> $ g++ -O4 main.cpp
fld#flap ~/work/p/test1
> $ g++ -O0 main.cpp
/tmp/cc8D7sNK.o: In function `__static_initialization_and_destruction_0(int, int)':
main.cpp:(.text+0x1c0): undefined reference to `B::ID'
collect2: error: ld returned 1 exit status
fld#flap ~/work/p/test1
> $ clang++ -O0 main.cpp
/tmp/main-c49b32.o: In function `__cxx_global_var_init.1':
main.cpp:(.text.startup+0x7a): undefined reference to `B::ID'
clang-8: error: linker command failed with exit code 1 (use -v to see invocation)
fld#flap ~/work/p/test1
> $ clang++ -O1 main.cpp
/tmp/main-cf18ee.o: In function `__cxx_global_var_init.1':
main.cpp:(.text.startup+0x3c): undefined reference to `B::ID'
clang-8: error: linker command failed with exit code 1 (use -v to see invocation)
fld#flap ~/work/p/test1
> $ clang++ -O2 main.cpp
fld#flap ~/work/p/test1
> $ clang++ -O3 main.cpp
If someone has any ideas what might be the reason, any hints are more than welcome.
You did not provide a definition of B::ID anywhere. It just happens that with higher optimization all accesses happened to be elided by the compiler.
You need to add the definition of a static member at toplevel scope:
const id_type B::ID;
If a static const data member is only read, it does not need a separate definition because compile time constants are not considered ODR-used (One Definition Rule).
The reason that you need the definition at all is that the map constructor expects std::map::value_type in the initializer list which is std::pair<const Key, T>. The constructor that gets picked in this case is pair( const T1& x, const T2& y );
In order to call this constructor the address of A::ID which is B::ID gets taken, which constitutes an ODR-use even for a constant.
Because the pair constructor is almost trivial in this case it gets inlined at higher optimization and the only reference to &B::ID disappears because B::ID's value is known and the pair can be directly initialized.
See also: static
If you are using C++17 or newer, you can also make B:ID constexpr instead of const, then you do not need a separate definition, because constexpr is implicitly inline (inline static const should also be OK).

Workaround for Clang "exception specification is not available until end of class definition" bug

Given this code:
template <typename>
struct Check { constexpr static bool value = true; };
struct A {
A() noexcept(Check<int>::value) = default;
};
Compiling with various versions of GNU g++ works fine, but it always fails with clang++ 5.0.1 (both with libstdc++ and libc++):
$ g++-4.9.4 test.cpp -c -o test -std=c++11 -Wall -Wextra
$ g++-5.4.0 test.cpp -c -o test -std=c++11 -Wall -Wextra
$ g++-6.4.0 test.cpp -c -o test -std=c++11 -Wall -Wextra
$ g++-7.2.0 test.cpp -c -o test -std=c++11 -Wall -Wextra
$ clang++ test.cpp -c -o test -std=c++11 -Wall -Wextra -Weverything
test.cpp:2:16: warning: 'constexpr' specifier is incompatible with C++98 [-Wc++98-compat]
struct Check { constexpr static bool value = true; };
^
test.cpp:5:39: warning: defaulted function definitions are incompatible with C++98 [-Wc++98-compat]
A() noexcept(Check<int>::value) = default;
^
test.cpp:5:9: warning: noexcept specifications are incompatible with C++98 [-Wc++98-compat]
A() noexcept(Check<int>::value) = default;
^
test.cpp:5:5: error: exception specification is not available until end of class definition
A() noexcept(Check<int>::value) = default;
^
test.cpp:5:18: note: in instantiation of template class 'Check<int>' requested here
A() noexcept(Check<int>::value) = default;
^
3 warnings and 1 error generated.
$ clang++ test.cpp -c -o test -std=c++11 -Wall -Wextra
test.cpp:5:5: error: exception specification is not available until end of class definition
A() noexcept(Check<int>::value) = default;
^
test.cpp:5:18: note: in instantiation of template class 'Check<int>' requested here
A() noexcept(Check<int>::value) = default;
^
1 error generated.
On Compiler Explorer this also seems to work for all versions of GCC newer 4.7.0 (including trunk), but fails for all Clang versions except for Clang 3.4.0, 3.5.0, 3.5.1 and trunk. So this seems like Clang bug.
Is it possible to work around this bug? How? Is this bug already tracked somewhere?
EDIT:
I tracked this bug down to Clang PR23383. As of now there is no notice about this being fixed in Clang although it seems to work with Clang trunk in Compiler Explorer.
This might be related to PR30860 (and C++ DR1330 as described in Richard Smith's comment on PR30860). It seems that the issue has something to do about when the contents of the noexcept() are parsed.
And so it turns out that one obvious workaround is to try to force the compiler to parse these contents elsewhere. One possible solution would be to provide the contents noexcept() as a constexpr member constant:
template <typename>
struct Check { constexpr static bool value = true; };
struct A {
A() noexcept(workaround) = default;
private: /* Work around Clang PR23383: */
static constexpr bool workaround = Check<int>::value;
};
Unfortunately, this does not work in all cases, e.g. such as this:
#include <type_traits>
struct Base { virtual ~Base() noexcept; };
struct OuterClass {
class InnerDerived: public Base {
private:
static constexpr auto const workaround =
std::is_nothrow_default_constructible<Base>::value;
public:
InnerDerived() noexcept(workaround);
};
class InnerDerived2: public InnerDerived {
private:
static constexpr auto const workaround2 =
std::is_nothrow_default_constructible<InnerDerived>::value;
public:
InnerDerived2() noexcept(workaround2);
};
};
The latter yields the error even when using Clang trunk in Compiler Explorer. Any ideas why?

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();
}

Can't compile program with clang

I`am trying to compile code bellow. GCC compile it, but clang not.
Error: no member named 'sa' in 'A' static void sf() {A::sa('j');}
What's problem?
test.cpp:
template<typename T>
class A
{
private:
public:
void f() {this->a('j');}
static void sf() {A::sa('j');}
#ifdef U
void a(char x) {}
static void sa(char x) {}
#endif
};
UPD:
I use compilers, that included in Android NDK r10c
gcc 4.9:
cd C:\Tools\android-ndk-r10c\toolchains\x86-4.9\prebuilt\windows-x86_64\bin
clang++.exe -c C:\Users\Barkov_V\Desktop\test.cpp
clang 3.5:
cd C:\Tools\android-ndk-r10c\toolchains\llvm-3.5\prebuilt\windows-x86_64\bin
i686-linux-android-gcc-4.9.exe -c C:\Users\Barkov_V\Desktop\test.cpp

Forcing template function instantiation in class

I have a function that is declared like:
template<typename T>
void MyFunction();
And a class:
template<typename T>
class MyClass
{
public:
typedef void (*Function_T)();
Function_T m_Func;
void DoSomething()
{
m_Func = &MyFunction<T>;
}
}
When I use the class, I undefined symbols error on MyFunction<T>.
If I change DoSomething to
void DoSomething()
{
m_Func = &MyFunction<T>;
return;
MyFunction<T>();
}
Everything works, but that looks like a workaround and will probably not work with optimization.
I cannot add
template void MyFunction<T>;
to the class because it says it cannot be in class. Is there any other way I can force instantiation of the function?
Edit:
I was able to write a test that fails, but in g++ it has a different message and actually a compiler error: http://ideone.com/RbMnh
Your code will work with optimization as well. Although, I don't know why simply m_Func = &MyFunction<T> doesn't work. GCC 4.3.4 compiles it fine. Which compiler you're using?
And you can also do this:
void DoSomething()
{
if ( false) MyFunction<T>();
m_Func = &MyFunction<T>;
return;
}
By the way, the function pointer type is incorrectly defined. It should be this:
typedef void (*Function_T)();
// ^^ put this!
Your code compiles fine for me using GCC, so I'm not sure if this solution solves your particular problem, but you can explicitly instantiate template functions like so:
// Template function defined:
template <typename T>
void MyFunction() {
// body
}
// Template function instantiated:
template void MyFunction<int>();
The issue can be either a compiler bug, or an error in the parts of the code that you are not showing. Try to build a minimal example that reproduces the problem, this is the minimal example that I have been able to produce, and compiles fine with both clang++ 2.8 and g++ 4.4/4.5:
drodriguez#drodriguez-desktop:/tmp$ cat test.cpp
#include <iostream>
template <typename T>
void function() {
}
template <typename T>
struct type {
typedef void (*Func)();
Func _f;
void f() {
_f = &function<T>;
}
};
int main() {
type<int> t;
t.f();
std::cout << t._f << std::endl;
}
drodriguez#drodriguez-desktop:/tmp$ /usr/bin/clang++ --version
clang version 2.8 (branches/release_28)
Target: x86_64-pc-linux-gnu
Thread model: posix
drodriguez#drodriguez-desktop:/tmp$ /usr/bin/clang++ -o test test.cpp && ./test
1
drodriguez#drodriguez-desktop:/tmp$ g++ --version
g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
Copyright (C) 2010 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
drodriguez#drodriguez-desktop:/tmp$ g++-4.4 -o test test.cpp && ./test
1