Is this code valid?
template<bool b>
struct s {
void f() const {
}
static void f() requires b {
}
};
void g() {
s<true>().f();
}
clang says yes, but gcc says no
<source>: In function 'void g()':
<source>:10:20: error: call of overloaded 'f()' is ambiguous
10 | s<true>().f();
| ~~~~~~~~~~~^~
<source>:3:14: note: candidate: 'void s<b>::f() const [with bool b = true]'
3 | void f() const {
| ^
<source>:5:21: note: candidate: 'static void s<b>::f() requires b [with bool b = true]'
5 | static void f() requires b {
| ^
Compiler returned: 1
https://godbolt.org/z/f4Kb68aee
If we go through [over.match.best.general], we get:
a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then [...]
The only argument is the object argument, and we have earlier that:
If F is a static member function, ICS1(F) is defined such that ICS1(F) is neither better nor worse than ICS1(G) for any function G, and, symmetrically, ICS1(G) is neither better nor worse than ICS1(F); otherwise,
So the premise holds: all arguments for one function have a conversion sequence no worse than the conversion sequence for the other function. So we move on to our tiebreakers...
for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,
The only argument that we could have a better conversion sequence for is the object argument, and as established, that one is equivalent. So this tiebreaker does not apply.
the context is an initialization by user-defined conversion (see [dcl.init], [over.match.conv], and [over.match.ref]) and [...]
Nope.
the context is an initialization by conversion function for direct reference binding of a reference to function type, [...]
Nope.
F1 is not a function template specialization and F2 is a function template specialization, or, if not that,
Nope.
F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2 according to the partial ordering rules described in [temp.func.order], or, if not that,
Nope.
F1 and F2 are non-template functions with the same parameter-type-lists, and F1 is more constrained than F2 according to the partial ordering of constraints described in [temp.constr.order], or if not that,
Aha! In this example, we have non-template functions with the same parameter-type-lists (both are just empty). The static member function is constrained and the non-static member function is not constrained, which is the most trivial kind of "more constrained" (see [temp.constr.order]).
As such, I think that clang (and msvc) are correct to accept the program and gcc is incorrect to reject it. (submitted 103783).
Your code is ill-formed according to C++20 standard class.static.mfct#2:
There shall not be a static and a non-static member function with the same name and the same parameter types ([over.load]).
There is no exception here for the presence of requires-clause to differentiate member functions, only same name and the same parameter types. And it is exactly our case: the same name is f, and the same parameter types is empty set.
So Clang and MSVC are wrong in accepting the code. But the diagnostics of GCC is definitely confusing.
With some minor tweaks in the code (removed const in not-static member function and get its address in the code), Clang and MSVC also show to have big problems with it:
template<bool b>
struct s {
void f() {}
static void f() requires b {}
};
int main() {
s<true>().f();
void (s<true>::*x)() = &s<true>::f;
}
Demo: https://gcc.godbolt.org/z/vdq9j63Gs
Related
I am writing a library with many function objects whose classes have several operator() overloads that do not depend on the state of the classes and do not alter it. Now, I tried to make my code work with many old-style APIs (it is not a random need, I actually had to deal with such APIs) and therefore decided to make the function objects convertible to any function pointer corresponding to one of the overloads. At some point, I realized that I had too many such conversions to function pointer operators and that I should theorically be able to write a single variadic conversion operator. Here is a class implementing such a variadic operator:
struct foobar
{
template<typename... Args>
using fptr_t = void(*)(Args... args);
template<typename... Args>
operator fptr_t<Args...>() const
{
return [](Args... args) {
// Whatever
};
}
};
As you can see, I used the lambda conversion to function pointer to implement the conversion operator, which is not a problem since every function object I have is stateless. The goal was to be able to use the class as follows:
int main()
{
void(*foo)(int) = foobar();
void(*bar)(float, double) = foobar();
}
g++ has no problem compiling this code with the expected semantics. However, clang++ rejects it with a template substitution failure error:
main.cpp:21:11: error: no viable conversion from 'foobar' to 'void (*)(int)'
void(*foo)(int) = foobar();
^ ~~~~~~~~
main.cpp:11:5: note: candidate function [with Args = int]
operator fptr_t<Args...>() const
^
1 error generated.
Note that clang++ has no problem with such conversion operators as long as no variadic templates are involved. If I use a single template parameter, it will have no problem compiling the code. Now, should the code above be accepted or rejected by the compiler?
A lambda can only be converted to a function pointer if it does not capture, so your code should work. This is justified in the standard 5.1.2/p6 Lambda expressions [expr.prim.lambda] (Emphasis Mine):
The closure type for a non-generic lambda-expression with no
lambda-capture has a public non-virtual non-explicit const conversion
function to pointer to function with C++ language linkage (7.5) having
the same parameter and return types as the closure type’s function
call operator. The value returned by this conversion function shall be the
address of a function that, when invoked, has the same effect as invoking the
closure type’s function call operator.
So I would file it as a CLANG bug.
As a work around for CLANG, you can convert it to a std::function as shown below:
struct foobar
{
template<typename... Args>
using fptr_t = void(*)(Args... args);
template<typename... Args>
operator std::function<void(Args...)>() const
{
return [](Args... args) {
//...
};
}
};
int main()
{
std::function<void(int)> f1 = foobar();
std::function<void(double, float)> f2 = foobar();
f1(1);
f2(2.0, 1.0f);
}
Live Demo
When I run this code with libc++:
struct foo
{
foo(int x) : x(x)
{}
int x;
};
int main()
{
const auto select_x = std::mem_fn(&foo::x);
foo f(1);
printf("%i\n", select_x(f));
}
I get an error like this:
mem_fn.cpp:16:20: error: no matching function for call to object of type
'const std::__1::__mem_fn<int foo::*>'
printf("%i\n", select_x(f));
^~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1224:11: note:
candidate function not viable: 'this' argument has type 'const
std::__1::__mem_fn<int foo::*>', but method is not marked const
operator() (_ArgTypes&&... __args)
^
It seems that libc++ is missing a const overload. It work using libstdc++. Is this a bug in libc++? Or does the standard require a const overload?
I don't see the standard specifying anything about the const-callability of the wrapper returned by mem_fn. From [func.memfn] (quoting N4140):
template<class R, class T> unspecified mem_fn(R T::* pm);
1 Returns: A simple call wrapper (20.9.1) fn such that the
expression fn(t, a2, ..., aN) is equivalent to INVOKE (pm, t, a2, ..., aN)
(20.9.2). fn shall have a nested type result_type that
is a synonym for the return type of pm when pm is a pointer to
member function.
2 The simple call wrapper shall define two nested types named
argument_type and result_type as synonyms for cv T* and Ret,
respectively, when pm is a pointer to member function with
cv-qualifier cv and taking no arguments, where Ret is pm’s
return type.
3 The simple call wrapper shall define three nested types
named first_argument_type, second_argument_type, and
result_type as synonyms for cv T*, T1, and Ret, respectively,
when pm is a pointer to member function with cv-qualifier cv and
taking one argument of type T1, where Ret is pm’s return type.
4 Throws: Nothing.
The reference to [func.def] (though simple call wrapper is actually defined in [func.require]) is equally unilluminating. This pretty much only guarantees that whatever it returns is usable directly.
As a quality of implementation issue, though, I see no reason why the wrapper shouldn't be const-callable, and it looks like this actually has been fixed over a year ago. You might want to try updating your XCode to see if you can pick up a more recent version of the library.
#include <iostream>
struct A {};
struct B : public A {};
template<typename T>
void foo(const T &x) { std::cout << "Called template" << std::endl; }
void foo(const A &a) { std::cout << "Called A" << std::endl; }
int main()
{
foo(A());
foo(B());
return 0;
}
This prints:
Called A
Called template
I was under the impression that a suitable non-template function would always be chosen over a template function. Can someone explain to me the resolution steps that lead to this somewhat surprising result?
I was under the impression that a suitable non-template function would always be chosen over a template function.
This only holds if the template and the non-template are equally good candidates. That's why the non-template is chosen for foo(A()).
However, in the case of foo(B()), using the non-template requires a derived-to-base conversion. So the function template is strictly better, and hence it's chosen.
The foo template instantiates into void foo(const B&). Consider what it would look like without templates:
void foo(const B &x) { std::cout << "Called template" << std::endl; }
void foo(const A &a) { std::cout << "Called A" << std::endl; }
I believe you'll agree calling foo(B()) should unambiguously pick the first one. That's exactly why the template is chosen.
n3376 13.3.3.1/6
When the parameter has a class type and the argument expression has a
derived class type, the implicit conversion sequence is a
derived-to-base Conversion from the derived class to the base class.
n3376 13.3.3.1/8
If no conversions are required to match an argument to a parameter
type, the implicit conversion sequence is the standard conversion
sequence consisting of the identity conversion (13.3.3.1.1).
Identity conversion has exact match rank due table in 13.3.3.1.1/table 12, but derived-to-base is worse, than identity.
So, compiler just have candidates in first case
// template after resolving
void foo(const A&)
// non-template
void foo(const A&)
Both has identity rank, but since first is function-template, second will be chosen.
And in second case
// template after resolving
void foo(const B&)
// non-template
void foo(const A&)
Only first has identity rank and will be chosen.
Can someone explain to me the resolution steps that lead to this somewhat surprising result?
you may look at Overload Resolution at cppreference.com:
http://en.cppreference.com/w/cpp/language/overload_resolution
in particular see the section Ranking of implicit conversion sequences
Extension of the Answer:
I tried to provide more clarification with an excerpt of the information from the aforementioned link:
A function template by itself is not a type, or a function, or any other entity. No code is generated from a source file that contains only template definitions. In order for any code to appear, a template must be instantiated: the template arguments must be determined so that the compiler can generate an actual function (or class, from a class template).
For that, the compiler goes through:
function template name lookup
template argument deduction
Down to here, the compiler has a couple of candidate function definitions which can handle the specific function call. These candidates are instannces of the template function as well as relevant non-template function definitions in the program.
But the answer to your question lies in fact here:
Template argument deduction takes place after the function template name lookup (which may involve argument-dependent lookup) and before overload resolution.
The fact that function overload resolution is performed after template function instantiation is the reason for the ouput of your code.
Now your specific case goes through overload resolution as the following:
Overload Resolution:
If the [previous] steps produce more than one candidate function, then overload resolution is performed to select the function that will actually be called. In general, the candidate function whose parameters match the arguments most closely is the one that is called.
.
.
.
...
F1 is determined to be a better function than F2 if implicit conversions for all arguments of F1 are not worse than the implicit conversions for all arguments of F2, and
1) there is at least one argument of F1 whose implicit conversion is better than the corresponding implicit conversion for that argument of F2
...
.
.
.
Ranking of implicit conversion sequences:
Each type of standard conversion sequence is assigned one of three ranks:
1) Exact match: no conversion required, lvalue-to-rvalue conversion, qualification conversion, user-defined conversion of class type to the same class
2) Promotion: integral promotion, floating-point promotion
3) Conversion: integral conversion, floating-point conversion, floating-integral conversion, pointer conversion, pointer-to-member conversion, boolean conversion, user-defined conversion of a derived class to its base
The rank of the standard conversion sequence is the worst of the ranks of the standard conversions it holds (there may be up to three conversions)
Binding of a reference parameter directly to the argument expression is either Identity or a derived-to-base Conversion:
struct Base {};
struct Derived : Base {} d;
int f(Base&); // overload #1
int f(Derived&); // overload #2
int i = f(d); // d -> Derived& has rank Exact Match
// d -> Base& has rank Conversion
// calls f(Derived&)
I have a question regarding the c++ function matching for parameters of types T and const T&.
Let's say I have the following two functions:
void f(int i) {}
void f(const int &ri) {}
If I call f with an argument of type const int then this call is of course ambiguous. But why is a call of f with an argument of type int also ambiguous? Wouldn't be the first version of f be an exact match and the second one a worse match, because the int argument must be converted to a const int?
const int ci = 0;
int i = 0;
f(ci); // of course ambiguous
f(i); // why also ambiguous?
I know that such kind of overloading doesn't make much sense, because calls of f are almost always ambiguous unless the parameter type T doesn't have an accessible copy constructor. But I'm just studying the rules of function matching.
Regards,
Kevin
EDIT: To make my question more clear. If I have the two functions:
void f(int *pi) {}
void f(const int *pi) {}
Then the following call is not ambiguous:
int i = 0;
f(&i); // not ambiguous, first version f(int*) chosen
Although both versions of f could be called with &i the first version is chosen, because the second version of f would include a conversion to const. That is, the first version is a "better match". But in the two functions:
void f(int i) {} and
void f(const int &ri) {}
This additional conversion to const seems to be ignored for some reason. Again both versions of f could be called with an int. But again, the second version of f would require a conversion to const which would make it a worse match than the first version f(int).
int i = 1;
// f(int) requires no conversion
// f(const int &) does require a const conversion
// so why are both versions treated as "equally good" matches?
// isnt this analogous to the f(int*) and f(const int*) example?
f(i); // why ambiguous this time?
One call involves an "lvalue-to-rvalue conversion", the other requires an identity conversion (for references) or a "qualification adjustment" (for pointers), and according to the Standard these are treated equally when it comes to overload resolution.
So, neither is better on the basis of differing conversions.
There is, however, a special rule in the Standard, section 13.3.3.2, that applies only if both candidates being compared take the parameter by reference.
Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if ... S1 and S2 are reference bindings (8.5.3), and the types to which the references refer are the same type except for top-level cv-qualifiers, and the type to which the reference initialized by S2 refers is more cv-qualified than the type to which the reference initialized by S1 refers.
There's an identical rule for pointers.
Therefore the compiler will prefer
f(int*);
f(int&);
over
f(const int*);
f(const int&);
respectively, but there's no preference for f(int) vs f(const int) vs f(const int&), because lvalue-to-rvalue transformation and qualification adjustment are both considered "Exact Match".
Also relevant, from section 13.3.3.1.4:
When a parameter of reference type binds directly to an argument expression, the implicit conversion sequence is the identity conversion, unless the argument expression has a type that is a derived class of the parameter type, in which case the implicit conversion sequence is a derived-to-base Conversion.
The second call f(i) is also ambiguous because void f(const int &ri) indicates that ri is a reference to i and is a constant. Meaning it says that it will not modify the original i which is passed to that function.
The choice whether to modify the passed argument or not is in the hands of the implementer of the function not the client programmer who mearly uses that function.
The reason the second call f(i) is ambiguous is because to the compiler, both functions would be acceptable. const-ness can't be used to overload functions because different const versions of functions can be used in a single cause. So in your example:
int i = 0;
fi(i);
How would the compiler know which function you intended in invoking? The const qualifier is only relevant to the function definition.
See const function overloading for a more detailed explanation.
I am having the following setup:
template <typename T>
void foo(T& t);
void foo(const int& t);
void f()
{
int i;
foo(i); //Unresolved reference to "void foo<int>(int &)"
foo(const_cast<const int&>(i)); //Unresolved reference to "void foo(int const &)"
}
In the first call to foo, the compiler tries to call the template version, since the argument of the non-template one does not match the type of i. In the second call the non-template version is called. I am using the Microsoft C++ compiler version 10. Is this standard behavior? If the type is not exactly matched, even if it only has a const modifier, then the template function is called?
EDIT: I know those two functions don't have definition, I am just pointing out what the linker complains about, to make it more clear what the compiler wants to call.
Yes, this behavior is correct according to the C++11 Standard.
In the first case, the argument is a reference to a non-const integer. Both overloads are viable to resolve this call, but the function template allows a perfect match, while the non-template overload requires a qualification conversion.
In the second case, both are a perfect match, but one of the overloads is not a function template, and therefore it is a better candidate than the function template. Per § 13.3.3/1, in fact:
Given these definitions, a viable function F1 is defined to be a better function than another viable function
F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then
— for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,
— the context is an initialization by user-defined conversion (see 8.5, 13.3.1.5, and 13.3.1.6) and the
standard conversion sequence from the return type of F1 to the destination type (i.e., the type of the
entity being initialized) is a better conversion sequence than the standard conversion sequence from
the return type of F2 to the destination type. [ ... ] or, if not that,
— F1 is a non-template function and F2 is a function template specialization, or, if not that,
— [...]
Is this standard behavior? If the type is not exactly matched, even if it only has a const modifier, then the template function is called?
Yes, that is well-defined by the Standard.
If there is no EXACT match, the template is used, because instantiated template version is always a better match than the one which requires conversion (even be it int & to int const& conversion).
This should work
#include <iostream>
template <typename T>
void foo(T& t) {}
void foo(const int& t){}
void f()
{
int i;
foo(i); //Unresolved reference to "void foo<int>(int &)"
foo(const_cast<const int&>(i)); //Unresolved reference to "void foo(int const &);
}
int main()
{
f();
}