I can't figure out why the following code compiles fine:
#include <iostream>
void bar(int x) {
std::cout << "int " << x << std::endl;
}
void bar(double x) {
std::cout << "double " << x << std::endl;
}
template <typename A, typename B> // Note the order of A and B.
void foo(B x) {
bar((A)x);
}
int main() {
int x = 1;
double y = 2;
foo<int>(x); // Compiles OK.
foo<double>(y); // Compiles OK.
return 0;
}
But if I switch the order of A and B as below, then it won't compile:
#include <iostream>
void bar(int x) {
std::cout << "int " << x << std::endl;
}
void bar(double x) {
std::cout << "double " << x << std::endl;
}
template <typename B, typename A> // Order of A and B are switched.
void foo(B x) {
bar((A)x);
}
int main() {
int x = 1;
double y = 2;
foo<int>(x); // error: no matching function for call to ‘foo(int&)’
foo<double>(y); // error: no matching function for call to ‘foo(double&)’
return 0;
}
EDIT: Ad-hoc explanations are welcome, but would be better if someone can point out exact what the spec. says. Thanks!
In the first one, the compiler knows that A is int because you specifically tell it so with foo<int>, and it knows that B is also int because of the parameter that you pass it. So both A and B are known or can be deduced (you could say: A is supplied, B is implied).
However, in the second one, since B comes first and A doesn't appear in the parameter list, the compiler can't tell what A is and gives you an error. You're explicitly telling it what B is with foo<int>, and then the parameter you pass is also a B which, at the call, is an int which agrees with your previous explicit definition of B, but no mention is made of A, implicitly or explicitly, so the compiler must stop and error.
You don't really need the standard for this, it's just common sense. What on earth would A be in the second one?
Thanks for asking this question though, because I didn't realise you could explicitly specify some parameters and implicitly specify others in the parameter list before this.
Related
If we have this example functions code in C++
void foo(int x) { std::cout << "foo(int)" << std::endl; }
void foo(int& x) { std::cout << "foo(int &)" << std::endl; }
Is it possible to difference what function to call doing any modification in the calling arguments?
If the function foo is called in some of these ways:
foo( 10);
i = 10;
foo( static_cast<const int>(i));
foo( static_cast<const int&>(i));
it's called the first foo overloaded function, because it can't pass by reference a const argument to a non-const parameter.
But, how would you do to call the second foo overload function?
If I call the next way:
int i = 10;
foo( i);
It happens an ambiguous error because both functions are valid for this argument.
In this link https://stackoverflow.com/a/5465379/6717386 it's explained one way to resolve it: using objects instead of built-in types and doing private the copy constructor, so it can't do a copy of object value and it has to be called the second foo overload function and passing the object by reference. But, is there any way with the built-in types? I have to change the name of function to avoid the overloading?
You may do a cast (of the function) to select the overload function:
static_cast<void (&)(int&)>(foo)(i);
Demo
In most instance, function overloading involves distinct parameter types and different input parameter lengths.
Your attempt is generally a bad practice and the resulting compiled code is compiler dependent and code optimization may even worsen things even more.
You may consider simply adding a second parameter to the second method, something like this:
void foo(int x) { std::cout << "foo(int)" << std::endl; }
void foo(int& x, ...) { std::cout << "foo(int &, ...)" << std::endl; }
where ... could be a boolean type, say: bool anotherFunction
So calling foo(param1, param2) would simply call the second code and everybody is fine.
Very strange design, but if you want... I'll offer a solution as strange as your design Use Xreference in function signature. Then in the function you can check what you need to do using std::is_lvalue_reference, std::is_rvalue_reference.
Something like this
template<class T>
void foo(T&& x)
{
static_assert(std::is_same<std::decay_t<T>, int>::value, "!");
if (std::is_rvalue_reference<T&&>::value)
std::cout << "do here what you want in foo(int x)";
else
std::cout << "do here what you want in foo(int & x)";
}
int main()
{
int x = 5;
foo(x); //"do here what you want in foo(int x)" - will be printed
foo(std::move(x)); //"do here what you want in foo(int & x)" - will be printed
}
Despite the good answer of #Jarod42, as an alternative solution you can rely on a templated entry point and the overloading of an internal function (if you don't want to deal with explicit casts, of course).
It follows a minimal, working example:
#include<type_traits>
#include<iostream>
#include<utility>
void foo_i(char, int x) { std::cout << "foo(int)" << std::endl; }
void foo_i(int, int &x) { std::cout << "foo(int &)" << std::endl; }
template<typename T>
void foo(T &&t) {
static_assert(std::is_same<std::decay_t<T>, int>::value, "!");
foo_i(0, std::forward<T>(t));
}
int main() {
foo( 10);
int i = 10;
foo( static_cast<const int>(i));
foo( static_cast<const int &>(i));
foo(i);
}
The static_assert serves the purpose of checking the parameter to be something that involves int (that is int, int &, const int &, int &&`, and so on).
As you can see from the code above, foo(i) will print:
foo(int &)
As expected.
Another one:
#include <iostream>
#include <functional>
void foo(int x)
{
std::cout << "foo(int)\n";
}
template<typename T>
void foo(T&& x)
{
std::cout << "foo(int&)\n";
}
int main()
{
int i = 10;
foo(i); // foo(int)
foo(std::ref(i)); // foo(int&)
}
I just happened to have stumbled upon this post and was surprised not to find the typical SFINAE solution. So, there you go:
#include <iostream>
#include <type_traits>
template<typename T,
typename std::enable_if<!std::is_lvalue_reference<T>{}, int>::type = 0>
void foo(T)
{ std::cout << "foo(int)" << std::endl; }
template<typename T,
typename std::enable_if<std::is_lvalue_reference<T>{}, int>::type = 0>
void foo(T&)
{ std::cout << "foo(int &)" << std::endl; }
int main() {
int i = 42;
int& r = i;
foo<decltype(i)>(i);
foo<decltype(r)>(r);
}
Live example
Can we use auto keyword instead of template?
Consider following example :
#include <iostream>
template <typename T>
T max(T x, T y) // function template for max(T, T)
{
return (x > y) ? x : y;
}
int main()
{
std::cout << max<int>(1, 2) << '\n'; // instantiates and calls function max<int>(int, int)
std::cout << max<int>(4, 3) << '\n'; // calls already instantiated function max<int>(int, int)
std::cout << max<double>(1, 2) << '\n'; // instantiates and calls function max<double>(double, double)
return 0;
}
So we can write it this way too :
#include <iostream>
auto max(auto x, auto y)
{
return (x > y) ? x : y;
}
int main()
{
std::cout << max(1, 2) << '\n';
std::cout << max(4, 3) << '\n';
std::cout << max(1, 2) << '\n';
return 0;
}
So, why should use auto keyword instead of template?
As #HolyBlackCat said in the comment, the snippets are not the same.
In the first snippet when you use templates, you confine the arguments of T max(T x, T y) to be of the same type. So if you take the template approach, the following code will not work:
int x = 3;
double y = 5.4;
max(3, 5.4);
However, if you take the second approach, you can compare two different data types (if permitted, of course). This is because both argument's auto will decide what it's going to get independently, so comparing a int and double in the second approach is totally valid.
Finally I found the answer to my question:
We can use abbreviated function templates if we're using the C++20 language standard. They are simpler to type and understand because they produce less syntactical clutter.
Note that our two snippets are not the same. The top one enforces that x and y are the same type, whereas the bottom one does not.
All try to do is to make this piece of code
int main() {
if constexpr( ??? ) {
std::cout << "Yes\n";
std::cout << f() << '\n';
std::cout << f(42) << '\n';
}
else {
std::cout << "No\n";
}
return 0;
}
compile if the function f is defined as in any of these examples
// Example 1
int f(int n = 0) { return n; }
// Example 2
int f(int n) { return n; }
int f() { return 0; }
// Example 3
int f(int n) { return n; }
and display Yes for examples 1 and 2, and display No for the example 3.
Is this even possible? I think I've seen someone doing this with SFINAE but I don't remember how exactly it was done and where exactly I saw that. Thank you in advance.
if constexpr can’t protect ill-formed code outside of any template (e.g., in main). The obvious thing to do is to write a template that accepts f itself as a template argument, but to do that you have to reify your overload set. The usual way to do that is as a SFINAE-friendly function object:
template<class F,class=void>
constexpr bool opt=false;
template<class F>
constexpr bool opt<F,decltype(std::declval<F>()(1),void(std::declval<F>()()))> =true;
template<class F> int use(F &&x) {
if constexpr(opt<F>) return x(1)+x();
else return 0;
}
const auto f_=[](auto &&...aa) -> decltype(f(std::forward<decltype(aa)>(aa)...))
{return f(std::forward<decltype(aa)>(aa)...);};
int main() {use(f_);}
In some cases there is also the option of creating a “fake” template that uses calls that are formally dependent but always use the types you want, but that’s impossible for a call f() with no arguments, which is ill-formed (possibly with no diagnostic required) immediately if your f requires an argument since it can’t depend on a template parameter.
I know that I shouldn't overload a function for just parameters differ only in one of them passed by copy and the other by reference:
void foo(int x)
{
cout << "in foo(int x) x: " << x << endl;
}
void foo(int& x)
{
cout << "in foo(int& x) x: " << x << endl;
}
int main()
{
int a = 1;
foo(5); // ok as long as there is one best match foo(int)
foo(a); // error: two best candidates so the call is ambiguous
//foo(std::move(a));
//foo(std::ref(an)); // why also this doesn't work?
}
So a code that uses std::bind can be like this:
std::ostream& printVec(std::ostream& out, const std::vector<int> v)
{
for (auto i : v)
out << i << ", ";
return out;
}
int main()
{
//auto func = std::bind(std::cout, std::placeholders::_1); // error: stream objects cannot be passed by value
auto func = std::bind(std::ref(std::cout), std::placeholders::_1); // ok.
}
So std::ref here to ensure passing by reference rather than by value to avoid ambiguity?
* The thing that matters me: Does std::bind() implemented some wrapper to overcome this issue?
Why I can't use std::ref in my example to help the compiler in function matching?
Now that you know passing by value and reference are ambiguous when overload resolution tries to compare them for choosing a best viable function, let's answer how would you use std::ref (or std::cref) to differentiate between pass-by-value and pass-by-reference.
It turns out to be ... pretty simple. Just write the overloads such that one accepts a int, and the other accepts a std::reference_wrapper<int>:
#include <functional>
#include <iostream>
void foo(int x) {
std::cout << "Passed by value.\n";
}
void foo(std::reference_wrapper<int> x) {
std::cout << "Passed by reference.\n";
int& ref_x = x;
ref_x = 42;
/* Do whatever you want with ref_x. */
}
int main() {
int x = 0;
foo(x);
foo(std::ref(x));
std::cout << x << "\n";
return 0;
}
Output:
Passed by value.
Passed by reference.
42
The function pass the argument by value by default. If you want to pass by reference, use std::ref explicitly.
Now let's answer your second question: how does std::bind deal with this type of scenario. Here is a simple demo I have created:
#include <functional>
#include <type_traits>
#include <iostream>
template <typename T>
struct Storage {
T data;
};
template <typename T>
struct unwrap_reference {
using type = T;
};
template <typename T>
struct unwrap_reference<std::reference_wrapper<T>> {
using type = std::add_lvalue_reference_t<T>;
};
template <typename T>
using transform_to_storage_type = Storage<typename unwrap_reference<std::decay_t<T>>::type>;
template <typename T>
auto make_storage(T&& obj) -> transform_to_storage_type<T> {
return transform_to_storage_type<T> { std::forward<T>(obj) };
}
int main() {
int a = 0, b = 0, c = 0;
auto storage_a = make_storage(a);
auto storage_b = make_storage(std::ref(b));
auto storage_c = make_storage(std::cref(c));
storage_a.data = 42;
storage_b.data = 42;
// storage_c.data = 42; // Compile error: Cannot modify const.
// 0 42 0
std::cout << a << " " << b << " " << c << "\n";
return 0;
}
It is not std::bind, but the method used is similar (it's also similar to std::make_tuple, which has the same semantic). make_storage by default copies the parameter, unless you explicitly use std::ref.
As you can see, std::ref is not magic. You need to do something extra for it to work, which in our case is to first decay the type (all references are removed in this process), and then check whether the final type is a reference_wrapper or not; if it is, unwrap it.
I came up with the following code when learning signal & slot, template, and function pointer.
Basically I am trying to make 2 classes, the base one will takes normal function pointers while the derived one will takes member function and wrap it up with a normal function, then pass it to the base class for invoking.
Here is the code:
#include<iostream>
struct foo {
void onNotify(int a, int b) {
std::cout << "member function: this=" << this << " a=" << a << " b=" << b << "\n";
}
};
void onNotify(void*, int a, int b) {
std::cout << "normal function: no context needed! a=" << a << " b=" << b << "\n";
}
// invoker that will takes normal functions.
template <typename...>
class invoker{
public:
invoker(void (*fptr)(void*, int, int), void* context){
fptr(context, 1, 2);
}
private:
invoker(){}
};
// invoker that will takes member functions.
template<class T>
class invoker<T> : public invoker<>{
public:
invoker<T>(T* context) : invoker<>(&forwarder, context){}
private:
invoker<T>(){}
static void forwarder(void* context, int i0, int i1) {
static_cast<T*>(context)->onNotify(i0, i1);
}
};
int main()
{
invoker<>(&onNotify, 0); // OK.
invoker<foo>(new foo); // OK.
invoker<foo>(0); // OK.
foo foo_;
auto f = invoker<foo>(&foo_); // OK.
// Errors:
// C2373 : 'foo_' : redefinition; different type modifiers.
// C2530 : 'foo_' : reference must be initialized.
invoker<foo>(&foo_); // ERROR!
return 0;
}
My questions are:
1) What is causing the compile error?
2) Why invoker<foo>(0); will actually run without error?
Thanks in advance!
1) The problem is that
invoker<foo>(&foo_);
is parsed as a definition of variable foo_ that has type invoker<foo>& rather than a call to the ctor of invoker<foo>. There is a number of ways to fix this, for example, use extra parentheses:
(invoker<foo>)(&foo_);
2) The code
invoker<foo>(0);
compiles without an error because it's unambiguous (it can't be interpreted as a declaration).