g++ 4.9.2 regression on pass reference to 'this' - c++

This is a minimized part of Pointer to implementation code:
template<typename T>
class PImpl {
private:
T* m;
public:
template<typename A1>
PImpl(A1& a1) : m(new T(a1)) {
}
};
struct A{
struct AImpl;
PImpl<AImpl> me;
A();
};
struct A::AImpl{
const A* ppub;
AImpl(const A* ppub)
:ppub(ppub){}
};
A::A():me(this){}
A a;
int main (int, char**){
return 0;
}
It compilable on G++4.8 and prior and works as well. But G++4.9.2 compiler raise following errors:
prog.cpp: In constructor 'A::A()':
prog.cpp:24:15: error: no matching function for call to 'PImpl<A::AImpl>::PImpl(A*)'
A::A():me(this){}
^
prog.cpp:24:15: note: candidates are:
prog.cpp:9:5: note: PImpl<T>::PImpl(A1&) [with A1 = A*; T = A::AImpl]
> PImpl(A1& a1) : m(new T(a1)) {
^
prog.cpp:9:5: note: no known conversion for argument 1 from 'A*' to 'A*&'
prog.cpp:2:7: note: PImpl<A::AImpl>::PImpl(const PImpl<A::AImpl>&)
class PImpl {
^
prog.cpp:2:7: note: no known conversion for argument 1 from 'A*' to 'const PImpl<A::AImpl>&'
But it can be fixed by small hack. If i pass '&*this' instead of 'this' then it bring to compilable state.
Is it G++ regression or new C++ standards feature which eliminate backward compatibility?

We can make a simpler example that compiles on neither g++ 4.9 nor clang:
template <typename T>
void call(T& ) { }
struct A {
void foo() { call(this); }
};
int main()
{
A().foo();
}
That is because this is, from the standard, [class.this] (§9.3.2):
In the body of a non-static (9.3) member function, the keyword this is a prvalue expression whose value
is the address of the object for which the function is called.
You cannot take an lvalue reference to a prvalue, hence the error - which gcc explains better than clang in this case:
error: invalid initialization of non-const reference of type A*& from an rvalue of type A*
If we rewrite call to either take a const T& or a T&&, both compilers accept the code.

This didn't compile for me with gcc-4.6, so it seems that gcc-4.8 is where the regression occurred. It seems what you want is to take A1 by universal reference, ie: PImpl(A1 && a1). This compiles for me with both gcc-4.6, gcc-4.8 and gcc-4.9.

Related

class template fails to compile when named lambda is used as template class argument or constructor argument

I'm currently experimenting with class template programming and I came across this weird behavior that I cant understand when passing a named lambda as its argument. Could somebody explain why (1) & (2) below does not work?
template<typename Predicate>
class Test{
public:
Test(Predicate p) : _pred(p) {}
private:
Predicate _pred;
};
int main(){
auto isEven = [](const auto& x){ return x%2 == 0; };
// Working cases
Test([](const auto& x){ return x%2 == 0; });
Test{isEven};
auto testObject = Test(isEven);
// Compilation Error cases
Test(isEven); // (1) Why??? Most vexing parse? not assigned to a variable? I cant understand why this fails to compile.
Test<decltype(isEven)>(isEven); // (2) Basically same as (1) but with a workaround. I'm using c++17 features, so I expect automatic class parameter type deduction via its arguments
return 0;
};
Compiler Error message: Same for (1) & (2)
cpp/test_zone/main.cpp: In function ‘int main()’:
cpp/test_zone/main.cpp:672:16: error: class template argument deduction failed:
Test(isEven);
^
cpp/test_zone/main.cpp:672:16: error: no matching function for call to ‘Test()’
cpp/test_zone/main.cpp:623:5: note: candidate: template<class Predicate> Test(Predicate)-> Test<Predicate>
Test(Predicate p): _p(p){
^~~~
cpp/test_zone/main.cpp:623:5: note: template argument deduction/substitution failed:
cpp/test_zone/main.cpp:672:16: note: candidate expects 1 argument, 0 provided
Test(isEven);
^
Please forgive my formatting, and compile error message snippet as it does not match exact lines. I'm using g++ 7.4.0, and compiling with c++17 features.
In C++, you can declare a variable as
int(i);
which is the same as
int i;
In your case, the lines
Test(isEven);
Test<decltype(isEven)>(isEven);
are compiled as though you are declaring the variable isEven. I am surprised that the error message from your compiler is so different than what I hoped to see.
You can reproduce the problem with a simple class too.
class Test{
public:
Test(int i) : _i(i) {}
private:
int _i;
};
int main(){
int i = 10;
Test(i);
return 0;
};
Error from my compiler, g++ 7.4.0:
$ g++ -std=c++17 -Wall socc.cc -o socc
socc.cc: In function ‘int main()’:
socc.cc:15:11: error: conflicting declaration ‘Test i’
Test(i);
^
socc.cc:10:9: note: previous declaration as ‘int i’
int i = 10;
As you said, this is a most vexing parse issue; Test(isEven); is trying to redefine a variable with name isEven, and same for Test<decltype(isEven)>(isEven);.
As you showed, you can use {} instead of (), this is the best solution since C++11; or you can add additional parentheses (to make it a function-style cast).
(Test(isEven));
(Test<decltype(isEven)>(isEven));
LIVE

Using curly braces to value-initialize temporary as initializer to static data member causes error

This very simple code code gives an error in GCC 6.0:
template<class T>
struct S {
// error: cannot convert 'T' to 'const int' in initialization
static const int b = T{};
};
int main() {
}
Strangely, if I use regular braces instead (T()) then the code compiles. Is this a bug? The code compiles fine in clang.
The reason that T() works is because the compiler interprets it as a function declaration which takes no argument. The compiling would be done with just an explicit casting:
static const int b = (const int) T{};

Workaround for GCC 4.9 constexpr bug

I have the following piece of code which represents an actual bigger piece of code:
#include <iostream>
using namespace std;
template<size_t N> class A {
public:
static constexpr size_t getN() {return N;}
};
template<size_t N> class B {
public:
void print() { cout << "B created: " << N << '\n';}
};
template <class T> class C {
public:
void set(T* a) {
t_ptr = a;
}
void create() {
constexpr int m = t_ptr->getN();
B<m> b;
b.print();
}
private:
T* t_ptr;
};
int main() {
constexpr int n = 2;
A<n> a;
C<A<n> > c;
c.set(&a);
c.create();
}
Compiling with g++ -o main main.cpp -std=c++11 and GCC/G++ 4.8.3 the expected output is received:
B created: 2
However, with GCC/G++ 4.9.1 the code does not compile, output:
main.cpp: In member function ‘void C<T>::create()’:
main.cpp:27:15: error: the value of ‘m’ is not usable in a constant expression
B<m> b;
^
main.cpp:26:27: note: ‘m’ used in its own initializer
constexpr int m = t_ptr->getN();
^
main.cpp:27:16: error: the value of ‘m’ is not usable in a constant expression
B<m> b;
^
main.cpp:26:27: note: ‘m’ used in its own initializer
constexpr int m = t_ptr->getN();
^
main.cpp:27:19: error: invalid type in declaration before ‘;’ token
B<m> b;
^
main.cpp:28:15: error: request for member ‘print’ in ‘b’, which is of non-class type ‘int’
b.print();
^
This is caused by a known bug in GCC 4.9: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59937 and in this older thread https://gcc.gnu.org/ml/gcc-bugs/2013-11/msg00067.html the usage of extern is proposed as a workaround. However, I am not able to get this workaround working.
Could you guys help me to make this code compile in GCC 4.9? Thank you!
Since this is not constexpr the access to this->t_ptr is not either.
clang's error is a bit more helpful
implicit use of 'this' pointer is only allowed within the
evaluation of a call to a 'constexpr' member function
Referring to:
N3690 5.19/2 (emphasis added)
A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:
— this, except in a constexpr function or a constexpr constructor that is being evaluated as
part of e;
Calling the static member function via the typename works
constexpr int m = T::getN();

std::throw_with_nested expects polymorphic type in C++11?

Why does this not compile (tried with Clang 3.4.2 and GCC versions 4.7.4, 4.8.3 and 4.9.1):
#include <exception>
struct E { E(int) {} };
int main() {
std::throw_with_nested(E(42));
return 0;
}
Errors from GCC 4.9.1:
In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.1/include/g++-v4/exception:163:0,
from test.cpp:1:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.1/include/g++-v4/bits/nested_exception.h: In instantiation of 'static const std::nested_exception* std::__get_nested_helper<_Ex>::_S_get(const _Ex&) [with _Ex = E]':
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.1/include/g++-v4/bits/nested_exception.h:104:51: required from 'const std::nested_exception* std::__get_nested_exception(const _Ex&) [with _Ex = E]'
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.1/include/g++-v4/bits/nested_exception.h:138:38: required from 'void std::throw_with_nested(_Ex) [with _Ex = E]'
test.cpp:6:31: required from here
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.1/include/g++-v4/bits/nested_exception.h:90:59: error: cannot dynamic_cast '& __ex' (of type 'const struct E*') to type 'const class std::nested_exception*' (source type is not polymorphic)
{ return dynamic_cast<const nested_exception*>(&__ex); }
^
Errors from Clang 3.4.2:
In file included from test.cpp:1:
In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.1/include/g++-v4/exception:163:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.1/include/g++-v4/bits/nested_exception.h:90:16: error: 'E' is not polymorphic
{ return dynamic_cast<const nested_exception*>(&__ex); }
^ ~~~~~
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.1/include/g++-v4/bits/nested_exception.h:104:40: note: in instantiation of member function 'std::__get_nested_helper<E>::_S_get' requested here
{ return __get_nested_helper<_Ex>::_S_get(__ex); }
^
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.1/include/g++-v4/bits/nested_exception.h:138:11: note: in instantiation of function template specialization 'std::__get_nested_exception<E>' requested here
if (__get_nested_exception(__ex))
^
test.cpp:6:8: note: in instantiation of function template specialization 'std::throw_with_nested<E>' requested here
std::throw_with_nested(E(42));
^
Does std::throw_with_nested in C++11 expect an argument with polymorphic type or is this a bug in the compiler or libstdc++?
It's a bug.
When I implemented it for libstdc++ in 2009 the spec in N2619 required E to be a polymorphic type, but the final spec in the 2011 standard is different and the implementation in libstdc++ was never changed.
This would appear to be a bug.
The standard says of std::throw_with_nested:
[[noreturn]] template <class T> void throw_with_nested(T&& t);
Let U be remove_reference<T>::type.
Requires: U shall be CopyConstructible.
Throws: if U is a non-union class type not derived from nested_exception, an exception of unspecified type that is publicly derived from both U and nested_exception and constructed from std::forward<T>(t), otherwise std::forward<T>(t).
§18.8.6 [except.nested]
It does indeed look like a bug (see other answers), ref §18.8.6/7. If not already derived from std::nested_exception, an unspecified type is used that is derived from E and nested_exception.
As a proposed work around whilst it is being fixed, explicitly derive from std::nested_exception or implement the destructor as virtual;
#include <exception>
struct E : std::nested_exception { E(int) {} };
// Alternative workaround... virtual destructor
// struct E { E(int) {} virtual ~E() {} };
int main() {
try {
std::throw_with_nested(E(42));
return 0;
}
catch (E&) {
}
}
Sample here.

C++ GCC Why this sfinae code can be compiled with GCC 4.7, but not with 4.8?

I like to use local classes in template classes to perform constructions like "static if". But I've faced with the problem that gcc 4.8 does not want to compile my code. However 4.7 does.
This sample:
#include <type_traits>
#include <iostream>
#include <string>
using namespace std;
struct A {
void printA() {
cout << "I am A" << endl;
}
};
struct B {
void printB() {
cout << "I am B" << endl;
}
};
template <typename T>
struct Test {
void print() {
struct IfA {
constexpr IfA(T &value) : value(value) {
}
T &value;
void print() {
value.printA();
}
};
struct IfB {
constexpr IfB(T &value) : value(value) {
}
T &value;
void print() {
value.printB();
}
};
struct Else {
constexpr Else(...) {}
void print() {
}
};
typename conditional<is_same<T, A>::value, IfA, Else>::type(value).print();
typename conditional<is_same<T, B>::value, IfB, Else>::type(value).print();
}
T value;
};
int main() {
Test<A>().print();
Test<B>().print();
}
Options:
g++ --std=c++11 main.cc -o local-sfinae
Task:
Given classes A and B with different interfaces for printing.
Write a generic class Test that can print both A and B.
Do not pollute either any namespace or class scope.
Description of the code:
This is only a clean example.
I use an approach like this, because I want to generalize the construction "static if". See, that I pass the arguments to IfA and IfB classes via their fields, not directly to the print() function.
I use such constructions a lot.
I've found that these constructions should not be in (pollute) class scope. I mean they should be placed in a method scope.
So the question.
This code can not be compiled with GCC 4.8. Because it checks ALL classes, even if they are never used. But it has not instantiate them in binary (I've commented the lines that cause errors and compiled it with gcc 4.8). Proof:
$ nm local-sfinae |c++filt |grep "::If.*print"
0000000000400724 W Test<A>::print()::IfA::print()
00000000004007fe W Test<B>::print()::IfB::print()
See, there is no Test::print()::IfB::print(). (See later: 'void Test::print()::IfB::print() [with T = A]')
The errors if I compile aforementioned code with gcc 4.8:
g++ --std=c++11 main.cc -o local-sfinae
main.cc: In instantiation of 'void Test<T>::print()::IfB::print() [with T = A]':
main.cc:36:9: required from 'void Test<T>::print() [with T = A]'
main.cc:49:21: required from here
main.cc:34:17: error: 'struct A' has no member named 'printB'
value.printB();
^
main.cc: In instantiation of 'void Test<T>::print()::IfA::print() [with T = B]':
main.cc:28:9: required from 'void Test<T>::print() [with T = B]'
main.cc:50:21: required from here
main.cc:26:17: error: 'struct B' has no member named 'printA'
value.printA();
^
Is it a GCC 4.8 bug?
Or is it GCC 4.7 bug? Maybe the code should not be compiled.
Or it is a my bug, and I should not rely on the compiler behavior/should not use such approach to implement "static if".
Additional info:
This simple code compiles on 4.7, but not on 4.8. I shortened it.
struct A {
void exist() {
}
};
template <typename T>
struct Test {
void print() {
struct LocalClass {
constexpr LocalClass(T &value) : value(value) {
}
T &value;
void print() {
value.notExist();
}
};
}
T value;
};
int main() {
Test<A>().print();
}
Errors:
main.cc: In instantiation of 'void Test<T>::print()::LocalClass::print() [with T = A]':
main.cc:16:9: required from 'void Test<T>::print() [with T = A]'
main.cc:22:21: required from here
main.cc:14:17: error: 'struct A' has no member named 'notExist'
value.notExist();
^
Have tested two GCC 4.8 versions: 2012.10 and 2013.02. Hope it is GCC 4.8 bug and it can be fixed.
LocalClass is not a template. The "not instantiated if not used" rule is only applicable to member functions of class templates.
That is, when Test::print() is instantiated, everything that is inside is brought to life, including the unused member of its local class.
There is no SFINAE in your code.
SFINAE applies during template argument deduction and argument substitution (the 'S' in SFINAE stands for substitution) but the only substitution in your program happens when substituting A for T in the template parameter list of Test, which doesn't fail.
You then call print() which instantiates Test<A>::print(), which doesn't involve any substitution, and you get an error because value.notExist(); is not valid.
SFINAE has to be used in substitution contexts, such as template argument deduction caused by a function call or when deducing template parameters with default arguments.