Consider the following program:
struct S {
enum E {
e
};
template<E> void f() = delete;
};
template<> void S::f<S::E::e>() {}
int main() {
S s;
s.f<S::E::e>();
}
GCC 5.4.0 compiles the code, while clang 3.8.0 fails:
$ clang++ -std=c++14 main.cpp
main.cpp:10:20: error: redefinition of 'f'
template<> void S::f<S::E::e>() {
^
main.cpp:8:20: note: previous definition is here
template<> void S::f<S::E::e>();
^
main.cpp:14:11: error: no matching member function for call to 'f'
s.f<S::E::e>();
~~^~~~~~~~~~
main.cpp:5:22: note: candidate template ignored: substitution failure [with $0 = S::E::e]
template<E> void f() = delete;
^
2 errors generated.
Is clang correct and GCC wrong or is it the opposite? Note that if the delete specifier is removed, then clang compiles the code.
this seems defect report Explicit specialization of deleted function template , as you can see from here the issue seems fixed in clang since 3.9.0.
Related
I had written some c++ code in Visual Studio and was trying to run it on my c++ code on a linux server. When I tried to compile it with G++ however, it failed to compile with tons of errors. I looked through the error and was able to simplify the problem to this:
template<int x>
struct Struct
{
template<int y>
static void F()
{
//Struct<x>::F<0>(); // compiles
//Struct<y>::G(); // compiles
Struct<y>::F<0>(); // does not compile?
}
static void G()
{
}
};
int main ()
{
Struct<0>::F<0>();
}
On Visual Studio this code compiles just fine but on G++ or Clang++, it fails to compile. Errors on G++ 8.3.0:
test.cpp: In static member function ‘static void Struct<x>::F()’:
test.cpp:9:19: error: expected primary-expression before ‘)’ token
Struct<y>::F<0>(); // does not compile?
^
test.cpp: In instantiation of ‘static void Struct<x>::F() [with int y = 0; int x = 0]’:
test.cpp:19:18: required from here
test.cpp:9:15: error: invalid operands of types ‘<unresolved overloaded function type>’ and ‘int’ to binary ‘operator<’
Struct<y>::F<0>(); // does not compile?
Errors on Clang++:
5691311/source.cpp:9:19: error: expected expression
Struct<y>::F<0>(); // does not compile?
^
See it live: https://rextester.com/AAL19278
You can change the compiler and copy the code to see the different errors.
Is there anyway I could get around this problem so that my code will compile on G++ or Clang++?
Original Code:
template<int x, int y>
ThisType add()
{
return ThisType::Create(this->x() + x, this->y() + y);
}
ResultPos to = p.add<0, 1>();
template<int x>
struct Struct
{
template<int y>
static void F()
{
Struct<y>::F<0>(); // does not compile?
}
};
should not compile. You need to specify for the compiler that F in fact requires a template list, since F is a dependent template type. Otherwise the compiler will assume that the next < is a smaller than.
template<int x>
struct Struct
{
template<int y>
static void F()
{
Struct<y>::template F<0>();
}
};
I assume Struct<x>::F<0> works, since the compiler already knows that the current type is Struct<x>, but it cannot know that y is the same as xin this case.
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
The following code uses boost-python to create a Python function callback. It compiles fine on clang and msvc, but not on gcc. The boost versions are identical.
#include <boost/python.hpp>
typedef void CallbackType();
struct TheStruct {
CallbackType *theMember;
};
BOOST_PYTHON_MODULE()
{
boost::python::class_<TheStruct>("TheStruct")
.def_readwrite("theFunction", &TheStruct::theMember);
}
An even more simplified version, without boost:
template<class T>
void runner(T const volatile*) { }
int main() {
void (*varname)();
runner(varname);
}
clang and msvc are happy. gcc tells me:
test.cpp: In function 'int main()':
test.cpp:6:19: error: no matching function for call to 'runner(void (*&)())'
runner(varname);
^
test.cpp:2:6: note: candidate: 'template<class T> void runner(const volatile T*)'
void runner(T const volatile*) { }
^~~~~~
test.cpp:2:6: note: template argument deduction/substitution failed:
test.cpp:6:19: note: types 'const volatile T' and 'void()' have incompatible cv-qualifiers
runner(varname);
Why does this fail in gcc, how can I find such documentation myself in the future, and how can I get it to compile?
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.
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.