Is g++ misbehaving with function template overloading? - c++

I took the following example from http://en.cppreference.com/w/cpp/language/function_template#Function_template_overloading
and clang (3.4) seems to be handling it just fine, while g++ (4.8.3) gives an 'ambiguous overload' error:
struct A {};
template<class T> struct B {
template<class R> void operator*(R&){ cout << "1" << endl; } // #1
};
template<class T, class R> void operator*(T&, R&) { cout << "2" << endl;} // #2
int main() {
A a;
B<A> b;
b * a; //prints 1
}
clang correctly prints 1 (as expected according to cppreference), while g++ gives this error:
test_templates.cpp: In function ‘int main()’:
test_templates.cpp:13:5: error: ambiguous overload for ‘operator*’ (operand types are ‘B<A>’ and ‘A’)
b * a; //prints 1
^
test_templates.cpp:13:5: note: candidates are:
test_templates.cpp:7:26: note: void B<T>::operator*(R&) [with R = A; T = A]
template<class R> void operator*(R&){ cout << "1" << endl; } // #1
^
test_templates.cpp:9:33: note: void operator*(T&, R&) [with T = B<A>; R = A]
template<class T, class R> void operator*(T&, R&) { cout << "2" << endl;} // #2
Is g++ actually misbehaving here?

This example is taken from the standard (this is the draft for c++11).
14.5.6.2 Partial ordering of function templates paragraph 3 example:
struct A { };
template<class T> struct B {
template<class R> int operator*(R&); // #1
};
template<class T, class R> int operator*(T&, R&); // #2
// The declaration of B::operator* is transformed into the equivalent of
// template<class R> int operator*(B<A>&, R&); // #1a
int main() {
A a;
B<A> b;
b * a; // calls #1a
}
So, the standard itself pretty much say this is legal code. I could copy-paste rules, but one might as well click link and jump to the relevant place. My point is only to prove this is a proper compilable code as defined by the standard.
For what it's worth on my debian clang 3.5.0 compiled it right away, clang 3.4.2 had to be executed with -std=c++11, g++ 4.9.1 reported ambiguity in all cases (I even tried 1y).
I am puzzled by clang behaviour, though. I thought it might have been ambiguous in earlier versions of c++, the rule to disambiguate was added as a part of c++11 and g++ didn't keep up. But clang 3.5 compiles it even with -std=c++98.

That call is ambiguos. GCC is right.
§13.5.2/1
Thus, for any binary operator #, x#y can be interpas either
x.operator#(y) or operator#(x,y). If both forms of the operator
function have been declthe rules in 13.3.1.2 determine which, if any,
interpretation is used.
And in this case, we do have both the member and nonmember function. The built-in version is not included because the left hand operator has class type.
If you called the operator explicitly, there would be no ambiguity. However, when the call is done through an operator (thus implicitly) there is nothing which can distinguish between member and nonmember, therefore they're both viable functions which, in this case, leads to an ambiguous function call.
Previous versions of clang report it as ambiguous as well: http://goo.gl/OWsJUv

Related

Difference between g++ and clang++ with enable_if

I want to write a function that returns an instance of a type T but behaves differently depending on how T can be constructed. Say I have structs like these
#include <type_traits>
#include <iostream>
struct A {};
struct B {};
struct C {
C(A a) {
std::cout << "C" << std::endl;
}
};
I want to create Cs by giving them an A. I have a struct like so that uses enable_if to choose one of two functions:
struct E {
template< bool condition = std::is_constructible<C, A>::value,std::enable_if_t<condition,int> = 0>
C get() {
return C{A{}};
}
template< bool condition = std::is_constructible<C, B>::value,std::enable_if_t<condition,bool> = false>
C get() {
return C{B{}};
}
};
This compiles fine with g++82 (and I think also g++9), but clang9 gives me the error
$ clang++ --std=c++17 main.cpp
main.cpp:26:12: error: no matching constructor for initialization of 'C'
return C{B{}};
^~~~~~
main.cpp:6:8: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'B' to 'const C' for 1st argument
struct C {
^
main.cpp:6:8: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'B' to 'C' for 1st argument
struct C {
^
main.cpp:7:3: note: candidate constructor not viable: no known conversion from 'B' to 'A' for 1st argument
C(A a) {
^
1 error generated.
even though the enable_if should hide that function. (I call E e; auto c = e.get();). If I don't hardcode C but instead use a template to pass in C it works in both compilers.
template<typename T>
struct F {
template< bool condition = std::is_constructible<T, A>::value,std::enable_if_t<condition,int> = 0>
T get() {
return T{A{}};
}
template< bool condition = std::is_constructible<T, B>::value,std::enable_if_t<condition,bool> = false>
T get() {
return T{B{}};
}
};
I don't understand why clang apparently typechecks the body of the function even though the function should be disabled by enable_if.
Both compiler are right,
http://eel.is/c++draft/temp.res#8.1
The validity of a template may be checked prior to any instantiation. [ Note: Knowing which names are type names allows the syntax of every template to be checked in this way. — end note ] The program is ill-formed, no diagnostic required, if:
(8.1)
- no valid specialization can be generated for a template or a substatement of a constexpr if statement within a template and the template is not instantiated, or
[..]
(8.4)
- a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not depend on a template parameter, or
return C{B{}}; is not template dependent, and wrong. clang is fine by diagnosing the issue.
Since you seem to have access to compilers supporting c++17 you could use if constexpr instead of enable_if to accomplish what you want.
#include <iostream>
#include <type_traits>
struct A {};
struct B {};
struct C {
explicit C(A a) {
std::cout << "C" << std::endl;
}
};
template<typename T>
struct False : std::false_type {};
struct E {
template<typename T = void>
C get() const {
if constexpr (std::is_constructible_v<C, A>) {
return C{A{}};
} else if constexpr (std::is_constructible_v<C, B>) {
return C{B{}};
} else {
static_assert(False<T>::value, "Error");
}
}
};
int main() {
const auto C{E{}.get()};
return 0;
}

Failure to deduce template argument std::function from lambda function

While exploring templates in C++, I stumbled upon the example in the following code:
#include <iostream>
#include <functional>
template <typename T>
void call(std::function<void(T)> f, T v)
{
f(v);
}
int main(int argc, char const *argv[])
{
auto foo = [](int i) {
std::cout << i << std::endl;
};
call(foo, 1);
return 0;
}
To compile this program, I am using the GNU C++ Compiler g++:
$ g++ --version // g++ (Ubuntu 6.5.0-1ubuntu1~16.04) 6.5.0 20181026
After compiling for C++11, I get the following error:
$ g++ -std=c++11 template_example_1.cpp -Wall
template_example_1.cpp: In function ‘int main(int, const char**)’:
template_example_1.cpp:15:16: error: no matching function for call to ‘call(main(int, const char**)::<lambda(int)>&, int)’
call(foo, 1);
^
template_example_1.cpp:5:6: note: candidate: template<class T> void call(std::function<void(T)>, T)
void call(std::function<void(T)> f, T v)
^~~~
template_example_1.cpp:5:6: note: template argument deduction/substitution failed:
template_example_1.cpp:15:16: note: ‘main(int, const char**)::<lambda(int)>’ is not derived from ‘std::function<void(T)>’
call(foo, 1);
^
(same for C++14 and C++17)
From the compiler error and notes I understand that the compiler failed to deduce the type of the lambda, since it cannot be matched against std::function.
Looking at previous questions (1, 2, 3, and 4) regarding this error, I am still confused about it.
As pointed out in answers from questions 3 and 4, this error can be fixed by explicitly specifying the template argument, like so:
int main(int argc, char const *argv[])
{
...
call<int>(foo, 1); // <-- specify template argument type
// call<double>(foo, 1) // <-- works! Why?
return 0;
}
However, when I use other types instead of int, like double, float, char, or bool, it works as well, which got me more confused.
So, my questions are as follow:
Why does it work when I explicitly specify int (and others) as the template argument?
Is there a more general way to solve this?
A std::function is not a lambda, and a lambda is not a std::function.
A lambda is an anonymous type with an operator() and some other minor utility. Your:
auto foo = [](int i) {
std::cout << i << std::endl;
};
is shorthand for
struct __anonymous__type__you__cannot__name__ {
void operator()(int i) {
std::cout << i << std::endl;
}
};
__anonymous__type__you__cannot__name__ foo;
very roughly (there are actual convert-to-function pointer and some other noise I won't cover).
But, note that it does not inherit from std::function<void(int)>.
A lambda won't deduce the template parameters of a std::function because they are unrelated types. Template type deduction is exact pattern matching against types of arguments passed and their base classes. It does not attempt to use conversion of any kind.
A std::function<R(Args...)> is a type that can store anything copyable that can be invoked with values compatible with Args... and returns something compatible with R.
So std::function<void(char)> can store anything that can be invoked with a char. As int functions can be invoked with a char, that works.
Try it:
void some_func( int x ) {
std::cout << x << "\n";
}
int main() {
some_func('a');
some_func(3.14);
}
std::function does that some conversion from its signature to the callable stored within it.
The simplest solution is:
template <class F, class T>
void call(F f, T v) {
f(v);
}
now, in extremely rare cases, you actually need the signature. You can do this in c++17:
template<class T>
void call(std::function<void(T)> f, T v) {
f(v);
}
template<class F, class T>
void call(F f_in, T v) {
std::function f = std::forward<F>(f_in);
call(std::move(f), std::forward<T>(v));
}
Finally, your call is a crippled version of std::invoke from c++17. Consider using it; if not, use backported versions.

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

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.

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

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.