code as follows:
#include <iostream>
#include<functional>
class TestCase {
public:
template<typename ...Args>
void myfun(Args&& ...args) {
sayhello(std::forward<Args>(args)...);
}
private:
void sayhello(const std::string& v, const std::string& v2) {
std::cout <<" ---1---- " << v << "," << v2 << std::endl;
}
};
template<typename ...Args>
void test(Args&& ...args) {
TestCase a;
auto f = std::bind(&TestCase::myfun<Args...>, &a,std::forward<Args>(args)...);
f();
}
int main() {
std::string a = "1";
std::string b = "2";
test(a,b); //ok
test("1","2"); //error
return 0;
}
why std::forward not work? I tried pass value by lvalue and it work,but pass value by rvalue not work.I confused with TestCase::myfun<Args...> ,should it be TestCase::myfun<Args&&...> or something else?
The problem is similar to that in std::bind and rvalue reference.
std::bind will always copy the arguments and store them. When you use "1", "2", TestCase::myfun<Args...> is instantiated with Args = const char &[2], while the arguments are stored as const char * (due to the copy), so the error occurs since the parameter const char &[2] does not match arguments of const char *.
When you use std::string("1"), std::string("2"), TestCase::myfun<Args...> is instantiated with Args = std::string (so the parameter type is std::string &&). The error still occurs since the parameter std::string && does not match the stored arguments, which are lvalues.
As you have found, using lambda is a proper solution.
Related
class Context {
public:
Context(){
field2values_["age"] = std::vector<int>{1,2,3};
}
const std::vector<int>& field2values(const std::string& field) const {
auto it = field2values_.find(field);
if (it == field2values_.end()) {
return default_ints_;
}
return it->second;
}
private:
std::map<std::string, std::vector<int>> field2values_;
std::vector<int> default_ints_;
};
Context ctx;
std::vector<int> ctx_field2values(const std::string& field) {
return ctx.field2values(field);
}
class Checker {
public:
explicit Checker():
user_field_values_(ctx_field2values),
user_field_values_nc_(ctx_field2values)
{}
void print(){
const auto& values = user_field_values_("age");
std::cout << "size=" << values.size() << std::endl; // unexpected: 18446744073709535740
const auto& values_nc = user_field_values_nc_("age");
std::cout << "size=" << values_nc.size() << std::endl; // expected: 3
}
private:
const std::function<const std::vector<int>&(const std::string&)> user_field_values_;
const std::function<std::vector<int>(const std::string&)> user_field_values_nc_;
};
int main() {
Checker checker;
checker.print();
}
As we all know, const reference to temporary variable will extend the its lifetime. But in the code above, it does not work for user_field_values_ while it works for user_field_values_nc_. I guess this is because the type of user_field_values_ does not match its initialization, namely ctx_field2values. But why is there such a difference? Can anyone explain in principle why this rule (const reference to temporary variable) does not take effect?
Thanks in advance.
It's the same reason the following produces a dangling reference:
int f() {
return 42;
}
const int& invoke_f() {
return f();
}
const auto& e = invoke_f(); // dangling!
Basically, when a temporary appears in a return statement, its lifetime is not extended. It gets destroyed at the end of the return statement. ([class.temporary]/(6.11))
The function call operator of user_field_values_ behaves just like the invoke_f above. It invokes ctx_field2values (which returns a vector<int>), and returns the result as a const vector<int>& -- a dangling reference.
In C++23, std::function will be able to recognize this pattern (by means of std::reference_converts_from_temporary) and reject it. But it requires compiler support, which AFAIK does not exist yet.
Question:
If you want, for example, a variadic function that takes arbitrary number of parameter Args&&...args, and prints all those arguments t times. What's more is that you want t to be defaulted to 1, so it prints all args one time by default.
The first thing you would try is:
template <typename ... Args>
void foo(Args... args, unsigned t = 1) {
for (unsigned i = 0; i < t; ++i) {
(std::cout << ... << args);
}
}
Apparently this doesn't work unless you explicitly pass in the template parameters:
// Error: expected 1 argument, got 2
foo(0, "Hello, world!");
Because default parameters are treated as normal parameters while template deduction, and the parameter pack would always be empty. This prevents you from making the function useful. (Related question)
I then decided to use aggregate initialization (especially designated initializer since c++ 20) to simulate a more powerful "default parameter". It looks like this:
struct foo_t {
unsigned t = 1;
template <typename ... Args>
void operator() (Args... args) {
for (unsigned i = 0; i < t; ++i) {
(std::cout << ... << args);
}
}
};
int main() {
foo_t{}("Hello, ", "World!\n"); // prints 1 line
foo_t{ 5 }(0, "Hello, world!\n"); // prints 5 lines
return 0;
}
Moreover, this may solve people's complaint that they cannot "skip" default function parameters, with the help of c++ 20 designated intializers:
struct bar_t {
const std::string& str = "Hello, world!";
int t = 1;
void operator() () {
for (int i = 0; i < t; ++i) {
std::cout << str << std::endl;
}
}
};
int main() {
// Skips .str, using the default "Hello, World!"
bar_t{ .t = 10 }();
return 0;
}
I am wondering whether there are any potential pitfalls to do this.
Background (Can be safely ignored)
So yesterday I was wandering around SO and encountered a question (but it was later deleted) that asked about how to combine default std::source_location parameter with variadic template:
template<typename... Args>
void log(Args&&... args, const std::experimental::source_location& location = std::experimental::source_location::current()) {
std::cout << location.line() << std::endl;
}
Apparently this does not work as expected, just as stated in the question. So I came up with the following code:
struct logger {
const std::experimental::source_location& location = std::experimental::source_location::current();
template <typename... Args>
void operator() (Args&&... args) {
std::cout << location.line() << std::endl;
}
};
int main(int argc, char** argv) {
logger{}("I passed", argc, "arguments.");
return 0;
}
But found out it can do more, thus this question.
There is at least one pitfall with lifetime (extension):
const std::string& str = "Hello, world!"; create dangling pointer, (No lifetime extension for member).
Following is fine:
void repeat_print(const std::string& str = "Hello, world!", int t = 1) {/*..*/}
int main()
{
repeat_print();
}
but following is not:
struct bar_t {
const std::string& str = "Hello, world!";
int t = 1;
void operator() () const { /*..*/ }
};
int main()
{
bar_t{}();
}
You might fix bar_t to take member by value, but then you would do extra copy in some cases.
I want to be able to store a pointer of a function in a struct or class, then I can call upon that function when a button is pressed? here is what I have:
struct INFO
{
std::function<int(int, int)> call_back;
};
class YO
{
public:
YO() {};
~YO() {};
int SUM(int A, int B) { return A + B; }
};
int main()
{
//std::function<int(int, int)> datFunc = SUM;
INFO info;
YO* yo = new YO();
info.call_back = yo->SUM;
//std::function<int(int, int)> func =;
std::cout << info.call_back(10, 10) << std::endl;
system("pause");
return 0;
}
I get errors:
Error C3867 'YO::SUM': non-standard syntax; use '&' to create a pointer to member FunctionPointertest
Error C2679 binary '=': no operator found which takes a right-hand operand of type 'overloaded-function' (or there is no acceptable conversion) FunctionPointertest
You need to also supply an instance of the host object to the function call, in this case of class YO. std::function supports this, amongst many conversions it can do, but then the prototype becomes
std::function<int(YO*, int, int)> call_back;
And when you call it:
info.call_back(&yo, 10, 10)
Some options to do what you want. Using the lambda is the best solution.
void func() {
INFO info;
YO yo;
YO* yo2 = new YO;
info.call_back = [&yo](int a, int b) {
return yo.SUM(a, b);
};
using namespace std::placeholders;
info.call_back = std::bind(&YO::SUM, std::ref(yo), _1, _2);
info.call_back = std::bind(&YO::SUM, yo2, _1, _2);
}
P.S. You don't usually want to use new in c++.
Here are a set of Variadic Template Classes that will enable you to do this with ease if you have C++17 available to you. The first class simply stores a generic version of a std::function of any type! The second class stores the first class through a member function and will register either a function pointer, a function object or a lambda. It also has another member function that will invoke it. I am currently using lambdas in this example. I have two lambdas, the 1st takes two int types adds them and returns an int as in your problem above. The 2nd takes two std::strings concatenates them then prints them to the screen but does not return any value. You can even expand this by having a std::vector<Functor<>> stored in the driver class. The register_callback would change slightly as to pushing them into the vector, and the call_back you have options. You could either call them all in one go, or search via an index value to call a specific one, but I'll leave that as an exercise to you.
#include <string>
#include <iostream>
#include <functional>
template<typename RES_TYPE, typename... ARG_TYPES>
struct Functor {
std::function<RES_TYPE( ARG_TYPES... )> func_;
};
template<typename RES_TYPE, typename... ARG_TYPES>
class Driver {
private:
Functor<RES_TYPE, ARG_TYPES...> functor;
public:
Driver() = default;
~Driver() = default;
void register_callback( const Functor<RES_TYPE, ARG_TYPES...> &func ) {
functor = func;
}
RES_TYPE call_back( ARG_TYPES... args ) {
return functor.func_( std::forward<ARG_TYPES>(args)... );
}
};
int main() {
// Function Type: int ( int, int );
Functor<int, int, int> func;
auto lambda = []( int a, int b ) { return a + b; };
func.func_ = lambda;
Driver<int, int, int> driver;
driver.register_callback( func );
int a = 3;
int b = 5;
std::cout << driver.call_back( a, b ) << '\n';
std::cout << driver.call_back( 7, 5 ) << '\n';
// Function Type: void ( string, string );
Functor<void, std::string, std::string> func2;
auto lambda2 = []( std::string str1, std::string str2 ) {
str1 = str1 + " " + str2;
std::cout << str1 << '\n';
};
Driver <void, std::string, std::string> driver2;
func2.func_ = lambda2;
driver2.register_callback( func2 );
std::string str1 = "Hello";
std::string str2 = "World";
driver2.call_back( str1, str2 );
driver2.call_back( "Generic", "Programming" );
return 0;
}
The output is:
8
12
Hello World
Generic Programming
If you notice with this code here; there is no need to mess with pointers or dynamic memory. This is all taken care of by the use of std::function for us and the default dtors of the classes.
I tried my best to design this with simplicity, readability while making it portable and generic as possible. I am sure there can be some improvements made, but I think this is in line of what you are asking for.
I have a question continuing the post Function passed as template argument. In the provided code:
#include <iostream>
void add1(int &v)
{
v+=1;
}
void add2(int &v)
{
v+=2;
}
template <void (*T)(int &)>
void doOperation()
{
int temp=0;
T(temp);
std::cout << "Result is " << temp << std::endl;
}
int main()
{
doOperation<add1>();
doOperation<add2>();
}
what about a third function which has a different parameter set layout, e.g.
double add3(double v1, double v2)
{
return v1+v2;
}
If this is not achievable using template at all, how do we pass an arbitrary function to another function? And how do we handle the parameter set with all kinds of possibilities? I know python may be able to do it by passing a tuple (kwargs**), but not sure about C/C++.
One form of passing a generic function to be called is a callable templated type:
#include <functional>
#include <iostream>
template<typename F>
void callFoo(F f) {
f();
}
int main() {
callFoo(std::bind([](int a, int b) {std::cout << a << ' ' << b;}, 5, 6));
}
callFoo takes a callable type, F, and calls it. Around this call, you can, for example, do timer work to time the function. In main, it's called with a lambda that has two parameters and the values given to those parameters bound to it. callFoo can then call it without storing the arguments. This is very similar to taking a parameter with the type std::function<void()>.
If, however, you don't want to use std::bind, you can pass in the arguments separately with a couple changes:
template<typename F, typename... Args>
void callFoo(F f, Args... args) { //ignoring perfect forwarding
f(args...);
}
int main() {
callFoo(/*lambda*/, 5, 6);
}
In these cases, passing void functions makes sense. Indeed, return values can be used as parameters and passed in with std::ref. If you plan on returning what the function returns, you'll have to handle the special case of the return type being void, as you can't assign to a void variable and return that. At this point, it's easier to direct you to my previous question on the matter. My use case for it turned out to be moot, but the solution works great for other uses.
This could possibly lead you closer to what you want:
#include <iostream>
void add1(int &v)
{
v+=1;
}
double add2(double v1, double v2)
{
return v1 + v2;
}
// 1 param version
template< class aRetType, class tP1 >
aRetType doOperation( aRetType (*aFunction)( tP1 aP1 ), tP1 valP1 )
{
return aFunction( valP1 );
}
// 2 param version
template< class aRetType, class tP1, class tP2 >
aRetType doOperation( aRetType (*aFunction)( tP1 aP1, tP2 aP2 ), tP1 valP1, tP2 valP2 )
{
return aFunction( valP1, valP2 );
}
// 3 param version and up is not given, but you get the trick.
int main()
{
int iTemp = 8;
doOperation< void, int& >( add1, iTemp );
std::cout << "Result is " << iTemp << std::endl;
double iResult;
iResult = doOperation< double, double, double >( add2, 2.2, 8.8);
std::cout << "Result is " << iResult << std::endl;
}
I wonder if there is any way to differentiate the function calls (with arrays as parameters) shown in the following code:
#include <cstring>
#include <iostream>
template <size_t Size>
void foo_array( const char (&data)[Size] )
{
std::cout << "named\n";
}
template <size_t Size>
void foo_array( char (&&data)[Size] ) //rvalue of arrays?
{
std::cout << "temporary\n";
}
struct A {};
void foo( const A& a )
{
std::cout << "named\n";
}
void foo( A&& a )
{
std::cout << "temporary\n";
}
int main( /* int argc, char* argv[] */ )
{
A a;
const A a2;
foo(a);
foo(A()); //Temporary -> OK!
foo(a2);
//------------------------------------------------------------
char arr[] = "hello";
const char arr2[] = "hello";
foo_array(arr);
foo_array("hello"); //How I can differentiate this?
foo_array(arr2);
return 0;
}
The foo "function family" is able to distinguish a temporary object from a named. Is not the case of foo_array.
Is it possible in C++11 ?
If not, do you think could be possible? (obviously changing the standard)
Regards.
Fernando.
There is nothing wrong with foo_array. It's the test case that is bad: "hello" is an lvalue! Think about it. It is not a temporary: string literals have static storage duration.
An array rvalue would be something like this:
template <typename T>
using alias = T;
// you need this thing because char[23]{} is not valid...
foo_array(alias<char[23]> {});